by Kelly Martin
Last updated: July 2, 2010
Configure an easy-to-maintain FreeBSD Unix web server using Apache, PHP and MySQL with layered security. Enable SSH Host Key encryption and install web services in a jail/CHROOT virtualized environment. Add additional layers of security with the Suhosin Hardened PHP security patch, the ModSecurity web application firewall, a strong packet filter firewall, and the AIDE file integrity monitor (a "Tripwire" style integrity monitor) with daily e-mail alerts sent to the administrator.
It's important to keep computer systems as simple as possible - simple to build, simple to update, and easy to monitor remotely to ensure everything is running as planned. With e-commerce systems, simplicity is relative to a defense-in-depth perspective when needing to handle money. The purpose of this article is to take a freshly installed FreeBSD system and create a secure, fully featured server that can process credit card transactions online and thwart hackers at the same time - and automate many common tasks involved in monitoring and maintaining the system.
A common problem today for administrators is how to keep web servers secure without limiting the types of dynamic web applications, web servers and databases that can be installed. Too often, software installed by users contain security vulnerabilities, discovered today or sometime in the future, that can and certainly will compromise a system. The risk of a compromising situation can be mitigated with layered security and active defense-in-depth maintenance and automation. Automated scripts written by the bad hackers troll the wide Internet for servers running vulnerable software that is easy to exploit. Full compromise can be had and remitted with a blink of an eye, leaving barely a trace. A good administrator needs to minimize the risk of web applications and database servers through architecture and design, plus tools that secure, monitor and report on the state of a web server.
Getting started
It is not difficult to get a core FreeBSD system running. On modern hardware, a basic install takes as little as five or ten minutes. But that is just a building block of Unix, and isn’t quite enough software just yet. In this article, we'll take the world’s most common web server configuration, Apache/PHP/MySQL, and put it in a CHROOT jail virtualization layer, add a strong firewall, add a web application firewall, add a file integrity monitor to notify us of any unwanted changes, and perhaps the Snort Intrusion Detection System. All along we'll use strong public-key authentication keys with pass-phrases for remote access.
Start by installing the base FreeBSD operating system with the core developer tools. Use the FreeBSD Manual for step-by-step instructions , if you need them, and you will quickly and easily get a system up and running. It is a remarkably well-written technical document for all levels of users. For most people, most default FreeBSD settings can be left alone for ease-of-use, and when set to “automatic” are just fine. Don't worry, most things that are installed in the default configuration can still be changed or turned Off/On at a later date, and a default install of FreeBSD is all that’s required for now.
1. Install the ports tree
Download the latest snapshot of the ports tree, as this will always be a newest copy available. The ports tree is used to add more software to the system in a simple way, and makes it easy to update in the future. Compiling ports will allow you a custom fit of applications on your specific architecture and CPU. Make sure you are ‘root’, the superuser, when performing all commands below, except where noted.
# portsnap fetch extract
In the future, the reader can use the command ‘portsnap fetch update’ to keep the ports tree current.
Now is a good time to install your favorite editor, such as the simple nano or pico editors if you are unfamiliar with Unix' default editor, vi. Nano a great editor for new users, simple to use and perfect for editing configuration files. It’s a clone of the pico editor that comes with popular Unix mail readers like pine, but has a few more advanced features such as syntax highlighting and being somewhat customizable.
# cd /usr/ports/editors/nano
# make install clean
2. Install portaudit for security vulnerability checking
Portaudit checks your installed ports for security audits, and once installed it will be run automatically before you install other ports or packages in the future. It will also be run on a daily basis, with the results e-mailed to you for offsite review.
cd /usr/ports/ports-mgmt/portaudit
make install clean
Then run it for the first time, which will also install the latest database:
portaudit -Fda
FreeBSD sends out two daily e-mails to the administrator (assuming the system's mail aliases have been setup), and one of them is a daily security e-mail. This e-mail will include the output from a daily run of portaudit, and will draw attention to any new vulnerabilities discovered in your installed ports. This is very useful! The output from portaudit will look something like this:
Checking for a current audit database:
Database created: Fri Jan 9 02:40:01 MST 2009
Checking for packages with security vulnerabilities:
0 problem(s) in your installed packages found.
3. Secure SSH
Adjust and secure SSH remote access immediately. Start with changing the default port it runs on to any arbitrary high port number to “hide” your SSH server from casual passer-bys. The most common attacks such as “brute force” password attack bots, which are automated bots that try to guess common passwords, often assume that the server is running on port 22, the default port. It doesn’t need to be. Changing the port only adds a very small extra layer of security, as any hacker with a port scanner can still find it easily, but it “reduces noise” in the /var/log/authlog file, making it easier to read, because the logs won’t be filled with the most mindless of attacks.
# cd /etc/ssh
# nano sshd_config
Search for the “Port” keyword and change the port to something else, to any number of your choice between 1,024 and 65,535. That’s a large number of ports to scan with a network scanner like nmap, so it takes time and dedication by a hacker to find your sshd port.
# Port 22
Port 12345
Having a line such as the above in your /etc/ssh/sshd_config file prevents automated bots, which assume your SSH server is running on port 22, from cluttering your logs with connection attempts. A dedicated attacker will still have no problem finding your SSH server, so we'll have to continue to secure it in other ways.
One your have edited the file, save it and restart the sshd server:
ps -aux|grep sshd
kill -s HUP [sshd process number]
The next step creates a SSH private key on a typical Unix laptop or desktop, such as Mac OS X or Linux. Private keys can also be easily created on Windows 2000/XP and Vista using the popular and free PuTTY tools, located at http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html. If you're using Windows, please follow the instructions for using the PuTTYgen tool to create an RSA key. Otherwise, for Mac and Linux users, simply setup your private key (if you haven’t already) using the commands below:
ssh-keygen -t rsa
cd ~/.ssh
cat id_rsa
cat id_rsa.pub
Note that the use of a passphrase is entirely optional. Most people will want to use a passphrase, which require the key plus the passphrase in order to access the server. If there is no passphrase, anyone possessing the key will have full access to the server.
Now copy your private key to the server you plan to work on. Regardless of whether you created your key using Mac OS X, Linux or Windows, copy your public (.pub) file to the server securely using a scp or sftp command such as the one below:
scp id_rsa.pub ssh-server:id_rsa_mydesktop.pub
Now login to the server and add this key to the your user's authorized_keys file:
mkdir .ssh
chmod 700 .ssh
cd .ssh
cat ../id_rsa_mydesktop.pub >> authorized_keys
Make sure the permissions on authorized_keys are set paranoid:
chmod 600 authorized_keys
Test that you can login now with SSH using key authentication instead of a password. If you can, then you’re ready to remove the password authentication from /etc/sshd_config, and then restart the sshd server again. That way, no one will ever be able to guess your password, because you use encryption keys (which can optionally have their own pass phrases embedded in them) instead of passwords.
At this point it’s a good idea to remove password authentication from the SSH daemon, so that only you with your authorized key will be able to login remotely. From the console, you can always still use a password. As the root superuser:
nano /etc/ssh/sshd_config
Make sure there is a line that reads PasswordAuthentication no. Otherwise, people will still be able to login using passwords, which you don't want when you start using public/private keys and keep them safe.
4. Setup the Packet Filter firewall, "pf"
Setting up the pf firewall will block access to all ports except those we explicitly want open, such as ports 80 and 443 for Apache and Apache/SSL, and an arbitrary port of your choosing for SSH. It is not required to have a blocked.txt file, but it useful if you get repeated attacks from hackers in certain parts of the world: you can simply add their ISP's entire CIDR address range into this blocked.txt file, and they will be blocked at the firewall.
cd /etc
touch blocked.txt
mv pf.conf pf.conf.orig
nano pf.conf
Before we create a pf.conf ruleset, we need to determine the addresses of our jails and configure pf to forward web requests to our applications in the correct jail. For the purposes of this article, the following is assumed:
- The server is on the Internet (and either has static IP addresses or uses DHCP)
- The jail will be at address 10.0.0.1
- We wish to filter traffic sent to both the jail and the host
Add the following simple ruleset (adjust interfaces as required)
#change interface below as required
ext_if="nfe0"
#change sshd port below to some other high port
sshd_port="45678"
webjail="10.0.0.1"
table <blockgeoip> persist file "/etc/blocked.txt"
scrub in
#Redirect web traffic to the jail.
rdr on $ext_if proto tcp from any to $ext_if port http -> $webjail port http
rdr on $ext_if proto tcp from any to $ext_if port https -> $webjail port https
#Allow jail traffic to nat back to anywhere
nat on $ext_if from $webjail to any -> ($ext_if)
#FILTERING RULES
block in
#block in quick inet6 all
block in log quick on $ext_if from <blockgeoip> to any
pass out keep state
pass quick on { lo }
antispoof log quick for { lo }
pass in on $ext_if proto tcp to ($ext_if) port { $sshd_port } keep state
pass out on $ext_if proto tcp to ($ext_if) port { $sshd_port } keep state
#Additional webjail rules. "pass out" not required because "nat pass" bypasses outgoing filters
pass in on $ext_if proto tcp to $webjail port { http, https } keep state
pass out on $ext_if proto tcp to $webjail port { http, https } keep state
Finally, make sure pf is added into /etc/rc.conf so that it starts automatically. We could edit rc.conf manually, or simply issue the following command and save a step:
echo pf_enable="YES" >> /etc/rc.conf
Either reboot for the changes to take effect, or simply issue the following command to start pf for the first time without rebooting:
/etc/rc.d/pf start
Note that we are using pf's excellent table command, which allows us to load a set of IP addresses to block from the /etc/blocked.txt file. This file can contain a list of individual IP addresses or a range of addresses in CIDR notation, one entry per line, in any combination. It is a great way to use geographic IP filtering at the firewall if, for example, your business does not require anyone from Asia to access your server but you see many web-based attacks from Asian IP addresses when you read your Apache logs.
In our ruleset above, if we had used rdr pass and nat pass instead of just rdr or nat, the redirection and nat rules would be performed without any filtering. In our case, we do want to filter requests that are sent to the jail, particularly the set of addresses in the table. The bonus is that the table filtering will work for services on both the virtualized jail and the host.
5. Setup a virtualized jail environment
A jail / CHROOT environment helps limit the impact of a server compromise by separating the web server from the main system. In the event of an incident where a web application vulnerability is exploited, we can be reasonably confident that the damage will be limited to the web server's jail. FreeBSD's jail capabilities extend well beyond simple CHROOT and provides virtualized environments that can interact with users on the Internet without exposing access to the host server in the event of a compromise. Later in this article, we'll also add a file integrity monitor to watch for unexpected changes in the jail so we'll know if a web application was compromised.
We'll use the ezjail tool to help create our jail environment, because it greatly simplifies the process and makes running multiple jails easy and resource-friendly.
cd /usr/ports/sysutils/ezjail/
make install clean
cp /usr/local/etc/ezjail.conf.sample /usr/local/etc/ezjail.conf
Edit the /usr/local/etc/ezjail.conf file and adjust as required. For our simple purposes, most of the defaults will be fine. You may want to change some of the defaults such as the jail locations, normally found in /usr/jails. Now install the base jail using the following command.
We will not install a copy of the ports tree inside the jail because later we'll just mount the host's port tree temporarily and just use that. Then we don't need to worry about updating two sets of ports trees.
ezjail-admin install
This will proceed to download a fresh copy of FreeBSD and install it as a basejail. If the administrator happens to run this command on an updated FreeBSD system that has security patches that are newer than a major release such as FreeBSD-RELEASE-7.2-p4 instead of RELEASE-7.2, the above command with query the administrator as to which version to install as the basejail. In this case simply select the RELEASE-7.2, which can be easily updated to security patch p4 after install.
Make sure the jails are started automatically at boot time my adding ezjail_enable="YES" to /etc/rc.conf:
echo ezjail_enable="YES" >> /etc/rc.conf
We will use the loopback interface for our jail. In this case, the address will be aliased to 10.0.0.1 since the jail needs to have an IP address.
ifconfig lo1 create
ifconfig lo1 inet 10.0.0.1 netmask 255.255.255.0
Adjust as required depending on your unique requirements; some administrators might choose an obscure address like 10.53.27.90 but others say simpler is best. Whatever you choose, remember to add it to /etc/rc.conf so the interface is started at boot.
nano /etc/rc.conf
Add the following two lines after your primary network interface:
cloned_interfaces="lo1"
ifconfig_lo1="inet 10.0.0.1 netmask 255.255.255.0"
Now add the following entry to the /etc/hosts file so the host system knows where to find the jail.
127.0.0.1 webjail
Create the jail using the same IP address as you chose above, and give it any name you like. In our case we'll call it "webjail".
ezjail-admin create webjail 10.0.0.1
The jail will be created quite quickly. The jail exists and is located at /usr/jails/webjail. It now needs a basic configuration just like any fresh FreeBSD system would. The configuration file to start up the jail is located at /usr/local/etc/ezjail/webjail in case you need to customize any of its default startup settings.
Copy the network resolver configuration file to the jail, so both systems can see the Internet.
cp /etc/resolv.conf /usr/jails/webjail/etc
Start the jail. On slow machines this make take some time.
/usr/local/etc/rc.d/ezjail.sh start
Mount the host's ports tree inside the jail in read-only mode:
D=/usr/jails/webjail
rm -rf $D/usr/ports
mkdir -p $D/usr/ports
mount_nullfs -o rw /usr/ports $D/usr/ports
Optional: It can be very useful to have the ports tree mounted inside the jail automatically upon boot. First, verify that the mount worked correctly by visiting /usr/jails/webjail/usr/ports and ensuring the ports three is there. Then edit the /etc/fstab of the host server and add the following entry to make it mount automatic. Caution! Any errors in the /etc/fstab file will prevent the server from booting completely, and will drop you into single-user mode upon boot until you edit and fix the problem in the fstab. If you reach this point you can edit /etc/fstab using vi and change or delete the line below and then reboot into a working system with this automatic mount.
# Device Mountpoint FStype Options Dump Pass#
/usr/ports /usr/jails/webjail/usr/ports nullfs rw 0 0
All set! Enter the jail as root:
jail /usr/jails/webjail webjail 10.0.0.1 /bin/sh
You are now in a fresh new FreeBSD jail, much like a virtualized server within your host server.
Many administrators will immediately try to ping an outside host from within the jail, to verify the network settings. This will not work however, as raw sockets are not allowed by default from within a jail. To temporarily enable ping to work from within the jail, issue the command sysctl security.jail.allow_raw_sockets=1 from the host environment.
Now would be an excellent time to install portaudit within the jail. Since you’re essentially in a new server, with the ports tree mounted, you can install it the same way as was done with the host server:
cd /usr/ports/ports-mgmt/portaudit
make install clean
If the time in your jail is wrong, you simply need to create a softlink from /etc/localtime to the appropriate time zone file. Time is important when analyzing logs. In my case, I am on Mountain Standard Time.
ln -s /usr/share/zoneinfo/America/Edmonton /etc/localtime
It’s a good idea to add an entry in your jail’s /etc/hosts file for itself:
127.0.0.1 webjail webjail
Finally, within the jail you should repeat step 2 so that security checks are enabled for all ports installed from the ports tree.
6. Install MySQL using ports
First, make sure you are inside the jail. We should install MySQL 5.0 (or a newer version, such at 5.1 or 6.x) before installing Apache and PHP. We’ll make sure we setup a strong password for the database root access, one that is different from the ‘root’ user’s shell password. Note that installing the MySQL server port will also compile and install the client binaries as well.
# cd /usr/ports/databases/mysql50-server
# make install clean
Add the MySQL startup to rc.conf, so that it starts automatically when the system boots:
# echo 'mysql_enable="YES"' >> /etc/rc.conf
Start the server
# /usr/local/etc/rc.d/mysql-server start
Set the root password! This step should never be skipped!
# /usr/local/bin/mysqladmin -u root password 'new-password1234+'
7. Install Apache version 2.2.x
Install and configure the latest Apache 2.2.x using the ports tree. There is no longer any reason to use the old Apache 1.3.x branch. It’s a very good idea to setup virtual hosting immediately as it can provide a small additional layer of security. We will also set the default web page to redirect visitors to a search engine (or other site).
Name-based virtual hosting makes web site enumeration more difficult for a hacker, as he does not know how many websites are being hosted by a given server, and thus cannot reach the domain we’re using for eCommerce without knowing more than just the IP address. If Apache's name-based virtual hosting is setup immediately, an attacker would need to query a full DNS or use the somewhat limited DNS tools for name-based virtual hosting available on the web to try to enumerate all the virtual host names hosted at a given IP address - this is a little harder than it may first appear. Additionally, since no web traffic should be expected on the default virtual host (which receives all traffic directed to the host's IP address but not a specific virtual host, such as a .com or .net), it will be interesting for the operator to watch the error logs of the default virtual host, and optionally log those requests to a different log file.
Start by installing Apache from the ports tree. Make sure you add the MySQL option.
# cd /usr/ports/www/apache22
# make install clean
Configure Apache 2.2.x as you would normally. The details of configuring Apache will not be covered in detail here, however the configuration file is heavily commented and easy to follow. For our purposes, we will make sure we enable MySQL support and disable mod_dav and mod_dav_fs, and leave the rest as defaults.
From within the jail, Apache's main configuration file is located at /usr/local/etc/apache22/httpd.conf, and from the host system, the same configuration file would intuitively be found at /usr/jails/webjail/usr/local/etc/apache22/httpd.conf (simply add /usr/jails/webjail to access the file when not within the jail). For our purposes, we need to edit and change DirectoryIndex to one that includes PHP file that end with .php:
DirectoryIndex index.php index.html index.htm
You will also need to change Apache’s Listen and ServerName directives in httpd.conf to the jail’s private address and port, or else Apache will not be able to start:
Listen 10.0.0.1:80
ServerName 10.0.0.1:80
Check your jail's rc.conf and make sure the hostname= is an FQDN (fully qualified domain name), else Apache will not start correctly. Alternatively, you could also set the hostname in /etc/rc.conf to anything of your choosing as long as you have a similar entry in the /etc/hosts file.
Edit your jail's rc.conf and add the following, putting in your domain name below:
hostname="somesite.com"
accf_http_load="YES"
apache22_enable="YES"
Start apache with apachectl start and if it works, surf to the page and verify it’s running
Reboot if you like, and Apache should start automatically.
Change the default Apache page to redirect to Google, or somewhere else you like:
# cd /usr/local/www/apache22/data
# nano index.html
Put the following data into index.html:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Google</TITLE>
<META HTTP-EQUIV="REFRESH" CONTENT="0; URL=http://www.google.com">
</HEAD>
<BODY>
</BODY>
</HTML>
The rest of your website(s) should be located in a different directory, such as /usr/local/www/apache22/sites.
8. Install PHP 5 using ports
Installing PHP 5 inside using the ports system makes it easy to stay up-to-date. In this case, we'll install PHP inside our jail with the Suhosin Hardened PHP security patch, which otherwise would need to be applied manually. Let's get going!
Note that at the time of this writing, there is a warning in the PHP port to not install the Suhosin patch within a jailed environment. A workaround has been discovered which we will get to in a few moments. For now, simply install PHP and include the Suhosin patch when prompted for compile options:
# cd /usr/ports/lang/php5
# make install clean
Make sure the PHP extensions are installed too! When prompted for which options to install, make sure to select "MySQL database support," and possibly “Curl,” or other extensions, depending on what you plan to do with your web server. Most of the defaults will work fine for our purposes.
# cd /usr/ports/lang/php5-extensions
# make install clean
Copy the default php.ini file to its correct location
cp /usr/local/etc/php.ini-dist /usr/local/etc/php.ini
Add the php type to the Apache httpd.conf file by running the following commands. In our case, we want the server to parts .html and .htm files to look for PHP code, if you do not want this then adjust the first line below accordingly.
echo "AddType application/x-httpd-php .php .html .htm" >> /usr/local/etc/apache22/httpd.conf
echo "AddType application/x-httpd-php-source .phps" >> /usr/local/etc/apache22/httpd.conf
Add a workaround that allows the Suhosin patch to work fine from within a jailed environment. Edit your jail's /usr/local/etc/php.ini file and add the following line at the end:
suhosin.apc_bug_workaround = 1
Now restart the Apache server using apachectl restart and you should be golden.
At this point the server’s ability to server up dynamic web pages and content is complete. The reader can proceed to load his or her web pages into the server, typically by adding virtual hosts into the Apache configuration file. Even if only a singe domain or site is going to be hosted, it can be useful to install the site (and all other sites - many are possible on a single server) using name-based virtual hosts.
A sample name-based virtual host configuration is listed below. It can be added to the configuration file found in /usr/local/etc/apache22/extra/httpd-vhosts.conf, which is read automatically when Apache is started.
#
# newdomain.com
#
<VirtualHost *:80>
ServerAdmin me@myemail.com
DocumentRoot "/usr/local/www/apache22/sites/newdomain.com"
ServerName newdomain.com
ServerAlias www.newdomain.com
<Directory />
AllowOverride None
Order deny,allow
Deny from all
</Directory>
<Directory "/usr/local/www/apache22/sites/newdomain.com">
Options Indexes FollowSymLinks
AllowOverride Options FileInfo
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
Once this entry has been made into the configuration file, the user will need to ensure that the directory exists before Apache is started, else it will not be able to find the web pages to serve up.
mkdir /usr/local/www/apache22/sites/newdomain.com
At this point we can restart Apache again (with apachectl restart) and start serving up dynamic, database-driven web pages with MySQL and PHP inside an Apache name-based host on a SSL-capable virtualized jail server with FreeBSD. The server could safely deliver e-commerce applications, but could still be hardened for security in a number of additional ways. The next steps are simple forays into additional defense-in-depth security.
9. Install the ModSecurity web application firewall
Now that the server is fully functional, let’s start to secure it. We’ll add ModSecurity which looks specifically for web application attacks and it does a pretty good job of finding and blocking the most common attacks.
cd /usr/ports/www/mod_security
make install clean
chmod 755 /usr/local/libexec/apache22/mod_security2.so
Ensure that mod_unique is already in your /usr/local/etc/apache22/httpd.conf configuration file, and add it if not:
LoadModule unique_id_module libexec/apache22/mod_unique_id.so
Also add an entry into httpd.conf so that ModSecurity is also loaded:
LoadModule security2_module libexec/apache22/mod_security2.so
At the time of this writing, the port installed the core ruleset automatically into /usr/local/etc/apache22/Includes/mod_security2/. Additionally, logging is done to /var/log/httpd-modsec2*.log which makes it easy to review ModSecurity-specific logs at a glance, right next to the default location of regular Apache log files in /var/log.
Note that the default configuration of ModSecurity is to detect attacks only; ModSecurity will not automatically block web-based attacks until it is told to do so. The administrator is advised to review the Apache error logs located in /var/log/httpd-error.log for some time to monitor the types of errors generated, make changes to the ModSecurity configuration as required, and ensure legitimate access to the web application will not be blocked. Once the administrator is confident of his configuration, he can change ModSecurity to “On” instead of “DetectOnly,” the default setting.
For now, we’ll restart Apache so the changes are put into effect:
apachectl restart
10. Maintain integrity of the filesystem
We will install a file integrity monitor to watch for unexpected changes on our new server. In the unlikely event that a PHP/MySQL web application is hacked and the server is compromised, we need to know exactly what files changed. We will install AIDE (Advanced Intrusion Detection Environment), which an open-source file integrity monitor similar to Tripwire, a commercial product. If any of your web applications are compromised (often because the operator failed to update those applications with the latest security patches), unwanted files may appear on the system. A good operator should read logs daily, particularly the output from the integrity monitor.
Use the ports tree to get AIDE installed quickly and easily.
# cd /usr/ports/security/aide
# make install clean
Edit AIDE’s configuration file, located in /usr/local/etc, and add your web directory, home directories, and so on. Below are a few example entries that could be added, this is the bare minimum and you will want to add more entries based on what you are trying to monitor:
/home/kel R-tiger-rmd160-sha1
/home/kel/.bash_history L
/root/.bash_history L
/usr/share/man L
/usr/share/openssl/man L
/usr/local/www R-tiger-rmd160-sha1
Since AIDE does not run as a daemon and does not have e-mail or cron capabilities built-in, we have to find another way to run AIDE automatically on a regular basis and get the results sent offsite for review by a human being. In our case, to keep things simple we’ll use the built-in FreeBSD periodic scripts to do this on a daily basis. The easiest way is to simply create an /etc/daily.local file that will get run each day, with the contents automatically e-mailed to the administrator offsite (assuming the administrator has put his e-mail address in the mail aliases files, as described below). Issuing the following command will create the daily.local file if it doesn’t exist and put one command in it:
echo "/usr/local/bin/aide --check" >> /etc/daily.local
Please note that many ISPs block the ability for your server to send e-mails directly - they often want you to use their SMTP mail server as a gateway to send mail, so they can catch spammers. If a day or two has passed after building your server and you have not received any of the automated daily e-mails FreeBSD servers generate by default, your ISP is likely blocking outgoing mail sent directly from your server.
Unfortunately Sendmail, an age-old mailer well known on the Internet, is rather difficult to configure to use an outgoing gateway without the user having prior experience of Sendmail, so in the next
11. Change the mailer to something easier to configure
Install postfix and configure the SMTP server to use a local gateway.
cd /usr/ports/mail/postfix
make install clean
Edit the rc.conf file to enable postfix at startup, and add the following:
sendmail_enable="NO"
sendmail_submit_enable="NO"
sendmail_outbound_enable="NO"
sendmail_msp_queue_enable="NO"
postfix_enable="YES"
Edit the /etc/defaults/periodic.conf file so that it reflects the following:
daily_clean_hoststat_enable="NO"
daily_status_mail_rejects_enable="NO"
daily_status_include_submit_mailq="NO"
daily_submit_queuerun="NO"
Finally, edit the /usr/local/etc/postfix/main.cf file to reflect the SMTP server. Search for ‘relayhost’ and then add your relay address nearby. In my case, my ISP is Shaw... please use your own ISP's mail relay and not mine below, otherwise it won't work.
relayhost = [shawmail.cg.shawcable.net]
Edit the aliases file located at /etc/mail/aliases. For some unknown reason, postfix ignores the aliases file created at /usr/local/etc/postfix/aliases, so please use the /etc/mail/aliases file that sendmail would otherwise use and you will have no problems. Ensure that a valid external e-mail address is set. This ensures that you get the daily logs generated by FreeBSD. Make sure the newaliases command is run manually after the file has been changed.
nano /etc/mail/aliases
newaliases
Finally, restart the server to make the changes complete.
12. General configuration & E-Mailing Off Daily Logs
Now would be a good time to ensure usernames like root and kel have the correct “names” associated to this server. Take a look at /etc/passwd to see if it’s correct, and if not issue something like:
pw usermod root -c 'Saturn &,,,'
pw usermod kel -c ‘Kelly Martin,,,’
13. Tell other servers we're alive (optional)
This step looks at a rudimentary way of tracking the location (IP address) and status of all your servers from one location. We can do this by writing a script in PHP to keep a database of this information, such that we can glance at a single page and see what servers are alive and doing fine.
Basically, w'ere going to install the text-based web browser Lynx and then create a cron job to ping one of our own websites to notify we’re alive. The contents of the "alive.php" script is outside the scope of this article... it could be just about anything you want it to be, including a blank file where access to that file is logged by the web server (don't forget to touch the file if it does not exist).
cd /usr/ports/www/lynx
make install clean
Try lynx and see if it works:
/usr/local/bin/lynx -dump "http://www.mywebsite.complete/myserver/alive.php"
Add the following to /etc/rc.local using the nano editor
#ping another server to say we're alive!
echo "ping www.mywebsite to say we're alive..."
/usr/local/bin/lynx -dump "http://www.mywebsite.com/serverdb/alive.php"
Drop down from root into a user-level account. This is important, as up to this point almost all work has been done at root level. Add a crontab entry into you crontab using the crontab -e command. Important Note: use a normal user’s crontab, not root’s!
# ping insurancelink.ca to say we're alive!!
10 * * * * /usr/local/bin/lynx -dump http://www.insurancelink.ca/servers/saturn.php > /dev/null
14. Staying Up-To-Date
An important part of keeping a system secure is to keep on top of new security vulnerabilities and install patches as soon as they become available. FreeBSD shines is this area with a number of tools that make this easy. However the first step is to ensure you on are the security-advisories@freebsd.org mailing list, which will notify you when new system patches are available.
If you install a different shell into your jailed server, you can more quickly access
To keep the system kernel and userland updated, there are a number of options. The easiest of these is the freebsd-update command. To fetch new updates, use the freebsd-update fetch command, followed by the freebsd-update install command. If any parts of the kernel were updated, you will need to reboot to install the kernel, otherwise you can continue to use the system. This command provides binary updates to the kernel and userland environment, but it also updates the source code in your /usr/src tree.
Since the jail environment uses the host’s kernel, it’s very important to keep the FreeBSD kernel up-to-date with security patches. The freebsd-update command while inside the host machine will keep the kernel updated plus the host’s userland, but it will not update the jails userland.
To update the jail’s user binaries, we need to issue the command ezjail-admin update -u. This will update the base-jail using freebsd-update.
To keep the ports tree updated, we will periodically run the command portsnap fetch update. This will update the ports tree in the host environment as well as the jail environment since our ports tree is mounted inside the jail as well.
We can easily check for known vulnerabilities in our installed ports using the portaudit -Fa command. Simply installing the tool makes it run automatically on a daily basis, as part of the /etc/periodic set of scripts, and this output will be e-mailed daily to the root user. So read the daily emails sent to you from this server, and it will indicate when it finds known vulnerabilities in installed software - a very cool security feature that covers many thousands of apps.
To check our installed ports versus the latest ports tree, we’ll use the pkg_version -v command to compare what is installed versus the latest version. There are a number of ways to upgrade installed ports, one of the easiest and most hassle-free is the portmaster utility, which can be found in /usr/ports/ports-mgmt:
cd /usr/ports/ports-mgmt/portmaster
make install clean
Then when you need to update a port, such as portaudit-0.5.14, you simply issue the portmaster portaudit command and it will be automatically compiled and upgrade to the latest version. Of course, use portmaster [installed port] to upgrade whichever port needs upgrading.
15. Conclusion
This article is updated periodically to reflect business needs and the changing security landscape. More importantly, the tools required to keep an e-commerce server are updated frequently and this article provides information on how to use some of these tools, and how to keep the overall system simple. The author appreciates comments on how to improve this article.
16. Appendix - List of To Do's
It would be a good idea to add a Snort Intrusion Detection System, either on the host or inline to watch for malicious traffic flows and provide yet one more way to protect against future bugs in installed software.