Back to Article Listing

Installing web services on FreeBSD

Warning

Use PHP at your own risk. (sorry, just a little joke... no, not really.. be careful)

I know there is already a lot of material about this topic, but... I set up another web server today and this time I took some notes. Maybe somebody will find them useful.

Have your FreeBSD installation securely patched and the ports collection updated. This does NOT cover chrooting or jailing. The installation process takes less than half a day. I am not exactly sure, because I wandered off during port compiles. (which was yet-another-reason to switch to OpenBSD)

My Goal is to set up a web server capable of serving open & encrypted pages (http & https) with popular software. I also want to be able to create dynamic (vs static) web pages and applications, with an option of using a database.

Online Documentation

(aka, required reading) These links take you away!

APACHE

I chose Apache 1.3, you may choose something else. I also chose mod_ssl so I can serve pages securely over SSL (https). As always, read the Makefile before beginning to look for flags. Let's get right to it:

cd /usr/ports/www/apache13-modssl
make

It seems that expat is always out to get me. The make stopped, and I had to deinstall and reinstall expat. I then came back to this directory and did a make again. Finally the screen below appeared:

+---------------------------------------------------------------------+
| Before you install the package you now should prepare the SSL       |
| certificate system by running the 'make certificate' command.       |
| For different situations the following variants are provided:       |
|                                                                     |
| % make certificate TYPE=dummy    (dummy self-signed Snake Oil cert) |
| % make certificate TYPE=test     (test cert signed by Snake Oil CA) |
| % make certificate TYPE=custom   (custom cert signed by own CA)     |
| % make certificate TYPE=existing (existing cert)                    |
|        CRT=/path/to/your.crt [KEY=/path/to/your.key]                |
|                                                                     |
| Use TYPE=dummy    when you're a  vendor package maintainer,         |
| the TYPE=test     when you're an admin but want to do tests only,   |
| the TYPE=custom   when you're an admin willing to run a real server |
| and TYPE=existing when you're an admin who upgrades a server.       |
| (The default is TYPE=test)                                          |
|                                                                     |
| Additionally add ALGO=RSA (default) or ALGO=DSA to select           |
| the signature algorithm used for the generated certificate.         |
|                                                                     |
| Use 'make certificate VIEW=1' to display the generated data.        |
|                                                                     |
| Thanks for using Apache & mod_ssl.       Ralf S. Engelschall        |
|                                          rse@engelschall.com        |
|                                          www.engelschall.com        |
+---------------------------------------------------------------------+
<=== src
===>  Creating Dummy Certificate for Server (SnakeOil)
      [use 'make certificate' to create a real one]

I wanted to create a self-signed cert, so without changing directories..

make certificate TYPE=custom
===>  Creating Test Certificate for Server
SSL Certificate Generation Utility (mkcert.sh)
Copyright (c) 1998-2000 Ralf S. Engelschall, All Rights Reserved.

Generating custom certificate signed by own CA [CUSTOM]

... answer all the questions. Note, when asked for FQDN, put the Primary DNS web address. The box may be called server123.domain.com, but will answer www.domain.com... so use the latter. Steps 7&8 encrypt your cert and server. They strongly recommend you to encrypt the server.key file with a Triple-DES cipher and a Pass Phrase.

When you have finished answering all the questions you will get:

Congratulations that you establish your server with real certificates.

Now do a make install When it is finished you need to edit /etc/rc.conf (see other article if needed) by adding 'apache_enable=YES' so it will start at boot. Now start Apache:

/usr/local/etc/rc.d/apache.sh start

and use a brower to test the http and https.

Hey, it worked!
The SSL/TLS-aware Apache webserver was
successfully installed on this website.

It looks like everything is going well, except one sticky point. Steps 7 & 8 in the cert creation will require you to type the pass-phrase everytime you start the server. While this is secure, it can be a pain. So, use the openssl program to encrypt the key with your pass-phrase. First list the keys to make sure we can proceed.

ls /usr/local/etc/apache/ssl.key/

Then copy the key so the original can be encrypted with the openssl command. You will need the pass-phrase again.. but only this once. When finished; restart Apache and tail the error logs to look for problems.

cp /usr/local/etc/apache/ssl.key/server.key /usr/local/etc/apache/ssl.key/server.key.crypt
openssl rsa -in /usr/local/etc/apache/ssl.key/server.key.crypt -out /usr/local/etc/apache/ssl.key/server.key
/usr/local/etc/rc.d/apache.sh restart
tail /var/log/httpd-error.log

Apache is rich, featureful software. You would do yourself a great deal of good reading the documentation, no kidding.

Virtual Hosting

Depending on the situation, I found Name-based Virtual Hosting sometimes fits my needs. Read the Apache documentation and decide for yourself what fits yours.

The sample IP address used here (192.168.0.111) does not have to be this machines address. It may be a common pool, or CARP, address. What is important is that DNS has all the web addresses below and maps them to that IP. DNS is not covered here.

Each virtual host below is different for different reasons. You can test both the DNS and Apache by creating the directories off the web path and putting a simple index.html file containing the server name, IP, and domain.

NameVirtualHost 192.168.0.111
<VirtualHost 192.168.0.111>
        ServerName      server157.domain.com
        DocumentRoot    /usr/local/www/data-dist/
        ErrorLog        logs/server157-error_log
        CustomLog       logs/server157-access_log common
</VirtualHost>
<VirtualHost 192.168.0.111>
        ServerName      domain.com
        DocumentRoot    /usr/local/www/data-dist/www.domain.com
        ErrorLog        logs/www-error_log
        CustomLog       logs/www-access_log combined
</VirtualHost>
<VirtualHost 192.168.0.111>
        ServerName      www.domain.com
        DocumentRoot    /usr/local/www/data-dist/www.domain.com
        ErrorLog        logs/www-error_log
        CustomLog       logs/www-access_log combined
</VirtualHost>
<VirtualHost 192.168.0.111>
        ServerName      support.domain.com
        DocumentRoot    /usr/local/www/data-dist/support.domain.com
        ErrorLog        logs/support-error_log
        CustomLog       logs/support-access_log combined
</VirtualHost>
<VirtualHost 192.168.0.111>
        ServerName      whitepapers.domain.com
        DocumentRoot    /usr/local/www/data-dist/whitepapers.domain.com
        ErrorLog        logs/whitepapers-error_log
        CustomLog       logs/whitepapers-access_log combined
</VirtualHost>
<VirtualHost 192.168.0.111>
        ServerName      some_other_domain.com
        DocumentRoot    /usr/local/www/data-dist/www.some_other_domain.com
        ErrorLog        logs/www-error_log
        CustomLog       logs/www-access_log combined
</VirtualHost>

Prevent serving certain files

I add another directive that is specific to using the PHP web scripting language. Many people tend to save include files with the .inc extension. If you do not want these pages ever served, just like .ht files, have apache deny them.

<Files ~ "^\.inc">
    Order allow,deny
    Deny from all
    Satisfy All
</Files>

restart the web

/usr/local/etc/rc.d/apache.sh restart

Make a direcotry private

First, create the main web directory, then a directory under that to protect

mkdir /usr/local/www/data-dist/www.domain.com/
mkdir /usr/local/www/data-dist/www.domain.com/webstats/

Now create an authentication directory, OUTSIDE the document path

mkdir /usr/local/www/webauth/

Use apache's tool to create entries in the password file to add a user:password (-c for create file, first time only) usage: htpasswd path/to/filename username

sample
htpasswd -c /usr/local/www/webauth/passwords username
    New password:
    Re-type new password:
    Adding password for user username
cat /usr/local/www/webauth/passwords
    username:QWerTY5uiOPHPbsd

# to add a user to a group (group: user1 user2 user3)
echo "apache: username webstats" > /usr/local/www/webauth/groups
cat /usr/local/www/webauth/groups
    apache: username webstats

# make sure your web server owns everything..
chown -R  www:www /usr/local/www/webauth

Now bring it all together by using the above creds by protecting a directory.. like statistics.. in the httpd.conf

<Directory "/usr/local/www/data-dist/www.domain.com/webstats/">
        AuthType Basic
        AuthName "webstats restricted"
        AuthUserFile /usr/local/www/webauth/passwords
        AuthGroupFile /usr/local/www/webauth/groups
        Require group apache
</Directory>

Log Analysis

For log analysis and statistics there are several choices; analog, webalizer, and visitors are popular. I have used all of them and they are easy to install and use, even on complex environments.

To illustrate, I have a web installation (not the box I did today) that has multiple domains and subdomains; mirrored on multiple servers tied together with CARP. (jealous?) So, analyzing the logs took a little planning and a little scripting. For most of the domains the logs were collected in different files just in case we wanted to look at them that way. But, it turns out, I could combine some of them for analysis. Others I wanted kept separate all the way through. I cron'd bash scripts to handle combining, taring, and ftp'ing the resulting files to a central server. Once there, I combine and sort them as needed before calling the log analysis applications on the central server each night. Each morning we have a fresh batch of web stats. Note: For that client, everyone; from executives down; claim they REALLY NEEDED web stats; but over time noone actually looks at them. I should know, I log those pages too... and I look at them. [grin]

OK, web server installed, tested, and spitting out pretty statistics!

PHP

PHP (recursive acronym for "PHP: Hypertext Preprocessor") is a widely-used Open Source general-purpose scripting language that is especially suited for Web development and can be embedded into HTML.

cd /usr/ports/www/mod_php5
make
make install
***************************************************************
Make sure index.php is part of your DirectoryIndex.
You should add the following to your Apache configuration file:
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
***************************************************************

Edit /usr/local/etc/apache/httpd.conf as recommended above.

Copy the recommended php.ini and make any edits you see fit.

cp /usr/local/etc/php.ini-recommended /usr/local/etc/php.ini

On FreeBSD, PHP installs pretty safely. But don't take my work for it. You should really check the whole php.ini file and read their superior online documentation for yourself. You should have an understanding of why switches are present and what the settings mean. As is true for almost ALL CONFIG files, leave yourself comments in the file when you make changes. This will help you track them down later -and- when upgrading the server.

This is a new setup so I can follow strict coding standards. I have a few pet peeves, so, I make sure the following are set. You may have to audit any old php scripts to meet these new standards.

  • short_open_tag = Off
  • error_reporting = E_ALL
  • register_globals = Off
  • allow_url_fopen = Off
  • safe_mode = On

PHP can report errors quietly to a log file or very loudly right to the browser. PHP catches all errors but only reports what you want it to report. You may want PHP to show [E_ALL] the errors of your ways, and want them in the browser; during development. This forces one to code more cleanly - to get rid of all the errors in your face. Alternately, you could just have PHP put errors to a log file and tail -f the log at a different prompt. Regardless, in production, I change the ini file to put E_ALL errors in log files only.

Next, I uncomment and set an include directory in the 'Paths and Directories' section. I can put sensative files, like db passwords, there and they will not be served because

  1. .inc files are not served [see Apache section] and
  2. I set the include directory to be outside the document path.

While you are in the ini file you may decide to change the directory settings that default to "/tmp", which is world readable. Have a look at session.save_path and mysql.default_socket. The later would require changes in its config file: my.conf. I have heard good arguments to change mssql.allow_persistent to Off. You may want to consider that. allow_url_fopen defaults to On, but I believe it poses a security risk. Better to have it Off globally then switched On as needed in a script.

Restart Apache and create a test file to serve up.

echo "<?php phpinfo() ?>" > /usr/local/www/data-dist/testfile.php

Then call that file from the browser to test PHP.

lynx https://www.domain.com/testfile.php

This should bring back gobs of data about your installation.

Important

After everything is working for you, you should delete that file before you go into production... well... because it delivers gobs of data about your installation, and that may be insecure.

PHP supports many databases. As of this writing: Adabas D, InterBase, PostgreSQL, dBase, FrontBase, SQLite, Empress, mSQL, Solid, FilePro (read-only), Direct, MS-SQL, Sybase, Hyperwave, MySQL, Velocis, IBM DB2, ODBC, Unix dbm, Informix, Oracle (OCI7 and OCI8), Ingres, Ovrimos.

See WhatCanDo for more details.

MYSQL

I chose MySQL. You may choose something else. Again, I wanted to try the lastest, so I chose version 5. But, any version should work. Please, read the Makefile in the port directory, and choose your own build flags.

Note if you are upgrading, you should read the MySQL Upgrade documentation.

cd /usr/ports/databases/mysql50-server
make WITH_LINUXTHREADS=yes WITH_OPENSSL=yes
make install

Important

I can not stress enough how important "WITH_LINUXTHREADS=yes" is to a smoothly running MySQL database on FreeBSD.

When the port finishes it gives several good hints. Read them! Here is a quick start:

Have a look at the different config options that come included and choose the one that fits your needs:

/usr/local/share/mysql/my-[small|medium|large|huge].cnf. As it states in the header of the file, you can copy one of them to my.cnf and make changes to it. The server will run with defaults if you do nothing. As mentioned in the PHP section, you may want to change the default socket in the [client] and [server] sections. The default location for databases on FreeBSD is /var/db/mysql. You are free to put the db's anywhere you want, as long as you mention it in the cnf.

# You can copy this file to
# /etc/my.cnf to set global options,
# mysql-data-dir/my.cnf to set server-specific options (in this
# installation this directory is /var/db/mysql) or
# ~/.my.cnf to set user-specific options.

Edit /etc/rc.conf again by adding mysql_enable=YES, so the db starts at boot. Then start the database for the first time.

/usr/local/etc/rc.d/mysql-server.sh start

Set local root password:

/usr/local/bin/mysqladmin -u root password 'new-password'

and if you need it, the network access root password:

/usr/local/bin/mysqladmin -u root -h machine.domain.com password 'new-password'

The online MySQL documentation is really very well done. Read that to set up users and databases.

PHP-MYSQL

We are not finished yet. If you go back to your browser and reload testfile.php script you will notice that mysql is still not listed. You need the php-mysql module to do that.

cd /usr/ports/databases/php5-mysql
make
make install

When I ran this on my box, it spit out what looked like an error "This port is deprecated; you may wish to reconsider installing it: Please use devel/automake19 instead.", but it was talking about the automake script not the php-mysql port. When it is finished, restart apache and check your testfile.php in a browser. You should see a mysql section.

Closing

OK, BAMP!! (a play on words from the linux community [LAMP])-- you have the basics out of the way. Now you just have to write a dynamic, data-driven, standards based, browser agnostic website with distinct separation of data, content, and markup!!

I apologize for any omissions, mistakes, or misleading assumptions.



Copyright © 20050109 genoverly
(db datestamp: 20070821)

nautical_flag_icon
Copyright © 2003-2015 genoverly