2009-10-28

OAMP: OpenBSD 4.6 + Chroot Apache + MySQL + PHP

Introduction
I'm combining the OAMP howto with chroot from the start this time because it's really the proper and secure thing to do. You can read more about how chroot works in my last article about it, but the premise is that chrooting Apache limits the amount of damage that can be caused by vulnerabilities in web applications. Keep in mind that we'll be accessing MySQL from within the chroot in this article, so all content within MySQL is potentially at risk if you're serving up SQLi-vulnerable content. The best things the average sysadmin can do to protect the server is to keep webapps and system patches up-to-date, and to perform periodic database dumps and system-wide backups.

I will walk through the commands here without showing the output they generate. You can reference my OAMP walk-through from OpenBSD 4.4 if you want to see example output, which should look similar for OpenBSD 4.6. The output shouldn't matter much, because I'll walk you through everything here.

Preparation
To start off, I make sure that a user-level admin account has access to run anything as root from sudo. Note: all the administrative commands in this post begin with "sudo" for a reason. To do this, I add my admin account to the wheel group. You can do this during the adduser process or with usermod, but if you created a non-root admin user during the OpenBSD 4.6 installation process, that user will be in the wheel group by default. All you need to do is add a sudo rule for the wheel group. It's commented out in /etc/sudoers.

$ su -
Password:
# visudo
... or use whatever editor you want on /etc/sudoers. Not recommended.

Find the line that grants access to the wheel group, and uncomment it. It's about 35-40 lines down in the default configuration. Optionally, there's a NOPASSWD version of the same, a few lines down. I don't recommend using this option on a production server, but it may make system management more friendly on your development servers and workstations.

%wheel ALL=(ALL) SETENV: ALL
-- or --
%wheel ALL=(ALL) NOPASSWD: SETENV: ALL

I also set up the path for pkg_add by adding these lines to my user-level account's .profile, then logging out and back in to reload the profile. I usually use an OpenBSD mirror, like ftp5.usa.openbsd.org instead of the main FTP site. You can also use any of the http mirrors in this path.
vi .profile

PKG_PATH=ftp://ftp5.usa.openbsd.org/pub/OpenBSD/4.6/packages/i386/
export PKG_PATH
Installing Packages
Installing php5-mysql and mysql-server will fetch all of the dependencies for OAMP. This particular version of PHP comes pre-compiled with the suhosin hardened PHP patches in place, which is a nice touch! This process may take a while depending on your connection speed. There are eight or nine packages in total, including php5-core and some perl modules that MySQL depends on for its management tools.
sudo pkg_add php5-mysql mysql-server
Next, copy the PHP + MySQL sample files into place
sudo cp /var/www/conf/modules.sample/php5.conf \
/var/www/conf/modules/

sudo cp /var/www/conf/php5.sample/mysql.ini \
/var/www/conf/php5/
Run the script to get the default MySQL database installed, start MySQL and set a MySQL root password.
sudo /usr/local/bin/mysql_install_db

sudo /usr/local/share/mysql/mysql.server start

sudo /usr/local/bin/mysqladmin \
-u root password 'your-password'
At this point, both MySQL and PHP are installed and set up with a default configuration that will probably work fine for most applications.

Chroot Setup
Most AMP packages only need somewhere to store Session information and a way to get to the MySQL socket. Since the real /tmp contains information that is not needed for Apache, we'll just create a new tmp directory specifically for Apache within /var/www and make it world-writable with the "sticky bit" set (exactly like the real /tmp)
sudo mkdir /var/www/tmp
sudo chmod 1777 /var/www/tmp
Next, reproduce the directory structure for the MySQL socket under /var/www.
sudo mkdir -p /var/www/var/run/mysql  # -p creates subdirs as needed
Start Apache and MySQL at boot
Set apache to start on boot by editing /etc/rc.conf. Find the httpd_flags line in the file, change NO to "" -- literally, two double quotes as shown below.
sudo vi /etc/rc.conf
# use -u to disable chroot, see httpd(8)
httpd_flags=""
-or-
httpd_flags="-u" #disables chroot. You can if you want.
Then, make sure that MySQL starts at boot and that the real mysql.sock file gets hard linked into the new directory by editing /etc/rc.local. I also added a line to remove the old hard link before starting MySQL. The end of my /etc/rc.local looks like this:

rm /var/www/var/run/mysql/mysql.sock
/usr/local/share/mysql/mysql.server start
ln /var/run/mysql/mysql.sock /var/www/var/run/mysql/mysql.sock

After getting all of the services set up to start automatically, I usually reboot to make sure everything starts up as expected.

sudo reboot

Testing
Once the system comes back online, the most basic test of Apache and PHP is to create a phpinfo script. This can be done with one line of shell-fu, which will launch "tee" with root permissions to write the phpinfo.php file.

echo "<?php phpinfo(); ?>" | sudo tee /var/www/htdocs/phpinfo.php

Then, navigate to http://your.openbsd.ip.address/phpinfo.php in your web browser. It should load a nice-looking document containing details about PHP's configuration. In particular, check for MySQL.


To really put our fresh chrooted OAMP installation through its paces, I downloaded the latest version of Wordpress, then followed the instructions using "the famous 5-minute install", which is way beyond the scope of this article. It's as simple as creating a database, setting up a privileged user for that database, editing a configuration file and copying wordpress into /var/www/htdocs (or a subdirectory) before accessing the control panel to finish up.

The wordpress install worked without changing anything from the instructions, and it's all running under chroot without any problems!


If you find that things are not working well with a particular AMP application, check file permissions, and copy or create hard links to files or directories that are needed. Example: sometimes you need a fake /etc/password file, some tools from /usr/bin or a /dev structure to be replicated within the chroot environment. Add these only as needed.

blog comments powered by Disqus