After having set up this development environment, I decided that someone else might benefit from the same information, so I've written this little guide for you
OK, first things first: I have just done a fresh net-install of CentOS 5.7 64-bit, which is the exact operating system on our latest servers. No other configuration has been done to this instance. The only package selection that was made was Server so otherwise it's clean, with no additional software installed.
Note that I use Nano as my editor in these examples. You may prefer other editors like Emacs, Vi, Pico etc. Simply replace the word nano with your choice of editor as necessary
Upgrading CentOS 5.7 to Apache 2.2
The first step is to ensure that SELinux is disabled, as it gets in the way somewhat
Ensure that it is disabled and save settings. If you needed to change any settings here then you need to force them to take effect
OK. Next we need to see what versions of Apache, if any, are available to us
yum list httpd*
Hopefully you see updates available. I see I can install to 2.2.3, so I'm going to do that
yum update httpd.x86_64 httpd-manual.x86_64
If that all completes without any errors, then we just need to tell Apache to start every time the system comes up
chkconfig --levels 235 httpd on
And that's Apache upgraded. Simple, eh?
Upgrading CentOS 5.7 to PHP 5.3
PHP 5.3 is not directly available for CentOS 5.7, where you only get PHP 5.1. So we're going to use the CentOSPlus repository to look for it
yum --enablerepo=centosplus list php5*
Ah, there it is! Currently I see PHP 5.3.3 available, which is not the latest version, but it's adequate for my purposes.
Now, installing it directly causes dependency issues with other installed PHP5.1 packages, so I'm going to uninstall PHP5.1 before I go any further. In fact, I'm just going to uninstall any PHP related packages
yum remove php*
Bye bye PHP 5.1 and all related packages! Now let's install all PHP 5.3 packages. Note that in this example I do a very broad "install all packages starting php53". You may want to be a little more specific
yum --enablerepo=centosplus install php53*
Hopefully that will complete with no errors and we can check that it's installed with this simple command
php -v PHP 5.3.3 (cli) (built: Jan 11 2012 13:54:48) Copyright (c) 1997-2010 The PHP Group Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
So far so good! Now lets test that PHP is installed and working OK by creating a simple test script
This is going to be as simple as it gets. Open PHP tag and call the phpinfo() function
Save that file and close the editor. We should start Apache now too
service httpd start
Now we'll visit the webpage and hopefully see the same PHP version displayed at the top of the page.
Note that the Server API will currently read Apache 2.0 Handler
Installing FastCGI (mod_fcgid) on CentOS 5.7
There are a few different ways of running PHP in Apache. Usually you have the option of running as an Apache module (which we are doing currently), via CGI or the newer (and not-suprisingly, faster) FastCGI.
Running as an Apache module (mod_php) is generally considered to be faster, and simpler. As we see, it's also the default in this case. However, I need to run it in FastCGI (mod_fcgid). The main reason being to replicate our live server configuration, but the reason we run in FastCGI on the live server is to protect websites from each other.
With the Apache module, you run every site in a single Apache instance that is owned by the specified Apache user (defaults to apache, a member of the group apache). This means that the same user will own the files of every website that you operate on this server, which therefore means that one website can cross over to the other's files and do things you probably don't want them to (like read config files and steal passwords). If you control the server completely yourself then this may not be a problem, but in our case we need to separate the various clients, and FastCGI allows us to do that. I've known some servers run the process as root, and I've been able to easily navigate and modify the entire filesystem via a simple PHP script. This is bad!
FastCGI runs a process for the user of the website that you're requesting. This user is restricted then to their own sites, of which there could still be many. They cannot see other sites on the same server, and therefore cannot steal any data. This is what we want.
It should be noted that FastCGI, while faster than standard CGI, is still slower than simply using mod_php.
Anyway, I want to use FastCGI, and I also want to configure the server to allow me to create multiple vhosts so that I can run many sites off of the same server with ease.
FastCGI isn't available directly from any CentOS repo, so we need to install the EPEL repository, which is a Fedora Special Interest Group's repo.
rpm -Uvh http://dl.fedoraproject.org/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm
The repository above recently moved from the old location at http://download.fedora.redhat.com/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm to the location above. Be aware!
Next, we want to install the YUM Priorities
yum install yum-priorities
Now we can install FastCGI
yum install mod_fcgid
Hopefully that's gone smoothly, and now we can make some config changes to PHP. Load up php.ini in to your editor of choice
Now head to the end of the file and enter this line:
cgi.fix_pathinfo = 1
Save the file and exit. Now we need to stop mod_php:
Comment out every line (# at the start), save the file and close the editor
Now restart Apache and hopefully it still starts OK
service httpd restart
If we now load up the test page again (ie http://hostname) then we should no longer see the PHP test script. This is because PHP support has been removed and Apache is no longer configured to handle PHP files
So, now we're going to prepare Apache to handle multiple vhosts. The way that I prefer to do this is to set up a vhosts directory within /etc/httpd/conf.d/ and every directory will have it's only configuration file. It's just easier to manage this way. You don't have to do it this way if you don't want to, but I recommend it, because even if you're only creating one site now, you might end up adding loads more at a later date and it's better to be safe than sorry. If you want to remove a site then all you have to do is to remove the config file for that site. Easy.
So, load up the Apache config file and let's tell it to look in this vhosts directory
Now search the file for a section like this:
# # Load config files from the config directory "/etc/httpd/conf.d". # Include conf.d/*.conf
Underneath it, add these lines:
# # Load vhost config files from the vhost config directory "/etc/httpd/conf.d/vhosts". # Include conf.d/vhosts/*
Next, we need to give priority to index.php over index.html etc. Find "DirectoryIndex" and add index.php to the start of the following list, so it looks something like this:
DirectoryIndex index.php index.html index.html.var
Next, search for a reference to "NameVirtualHost" and uncomment it so that it reads as follows:
Save the file and exit your editor
Now we create the vhosts directory that all of your site's config files will go into
Now, we're going to call FastCGI via suexec. However, suexec cannot use symlinks and it should have a document root of /var/www. We'll check that before we proceed:
Now we're looking for the AP_DOC_ROOT value, which should read like this:
Excellent! So, within /var/www we will create a directory where we can put in some wrapper scripts that will create the instance of FastCGI running as your chosen user
mkdir -p /var/www/fcgi/
Now we shall create the first vhost. It will be called web1. We shall also create a new group called web1 and a user called web1, who will be a member of the web1 group. Following that?
groupadd web1 useradd -s /bin/false -d /var/www/vhosts/web1 -m -g web1 web1
We now have a web1 group and a web1 user who has no shell access and his home directory is /var/www/vhosts/web1
You'll probably have had an error about the home directory after that last command. We're going to create it now and deal with any permissions and ownership necessary. Because web1:web1 will be the user that this website runs under, web1:web1 needs to have ownership of the directory
mkdir -p /var/www/vhosts/web1/httpdocs chmod -R 755 /var/www/vhosts/web1 chown -R web1:web1 /var/www/vhosts/web1
So, we now have the /var/www/vhosts home directory for the web1 user, and within that we have created the httpdocs directory for the web files to go in. Why the extra directory? Well it's always wise to allow some space outside of the public web root for secure files to be stored. It might even be wise, if you're the one designing the web site, to put all of your code in /var/www/vhosts/web1/codebase for example, and have /var/www/vhosts/web1/httpdocs/index.php refer back to ../codebase/controller.php... if you see where I'm going with that?
Anyway, that bit out of the way, we now need to create the FastCGI wrapper script, that will initiate the instance of FastCGI when necessary
mkdir /var/www/fcgi/web1 nano /var/www/fcgi/web1/fcgi
So, within the /var/www/fcgi directory that we created earlier, we have created a web1 directory and an fcgi wrapper script within it. This is like the vhosts directory that we created earlier, with the web1 config file in. Making it easy to administer, remember?
Anyway, in this script, enter the following:
#!/bin/sh PHPRC=/etc/ export PHPRC export PHP_FCGI_MAX_REQUESTS=500 export PHP_FCGI_CHILDREN=2 exec /usr/bin/php-cgi
The PHP_FCGI_MAX_REQUESTS value refers to the maximum number of requests that can be made before a FastCGI process is stopped and a new one is launched. PHP_FCGI_CHILDREN defines the number of PHP children that will be launched. Edit both as necessary, but this should be fine for now
The wrapper script that we just created needs to be executable, and the web1 user needs to have ownership. This is different from the vhosts config as they are all loaded by a single process
chmod 755 /var/www/fcgi/web1/fcgi chown -R web1:web1 /var/www/fcgi/web1
Now we'll create the vhost entry for this site
Enter this information, editing for your exact directories/filenames as necessary:
<VirtualHost *:80> ServerName www.web1 ServerAlias web1 ServerAdmin webmaster@localhost DocumentRoot /var/www/vhosts/web1/httpdocs/ <IfModule mod_fcgid.c> SuexecUserGroup web1 web1 PHP_Fix_Pathinfo_Enable 1 <Directory /var/www/vhosts/web1/httpdocs/> Options +ExecCGI AllowOverride All AddHandler fcgid-script .php FCGIWrapper /var/www/fcgi/web1/fcgi .php Order allow,deny Allow from all </Directory> </IfModule> # ErrorLog /var/log/apache2/error.log # CustomLog /var/log/apache2/access.log combined # ServerSignature Off </VirtualHost>
Now restart Apache and hopefully there will be no errors
service httpd restart
Now, let's copy over that test script that we used in the original installation and see whether we're now running web1 in FastCGI mode or not
cp /var/www/html/index.php /var/www/vhosts/web1/httpdocs/
Now we load this page in to the browser. Bear in mind that unless you've set your new site up in DNS then you'll need to add the IP to your HOSTS file. In my case I just added:
192.168.10.18 web1 192.168.10.18 www.web1
So I load the page up no problem, I see PHP Version 5.3.3 at the top, and I see the server API says...
Installing MySQL 5.5 on CentOS 5.7
The next, and final stage, is to install MySQL Server v5.5 on to this operating system. The default client version is 5.0.77 which is pretty old and I don't have any MySQL Server installed. We can soon have that sorted!
Firstly we need to get the Remi repository
rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-5.rpm
Now let's take a look at what's available
yum --enablerepo=remi list mysql mysql-server
Notice that in a clean install that yum reports that mysql_x86_64 is installed? As I mentioned a moment ago, this is the client. It's not the server daemon, so we need to get that. The latest version I see at the moment is 5.5.20, which is exactly what I'm looking for!
yum --enablerepo=remi install mysql.x86_64 mysql-server.x86_64
Now notice that I specifically instructed yum to install the x86_64 versions? The reason being that in the 32-bit version, some of the language files are missing, and if you install that then you end up with an error like this:
Error message file '/usr/share/mysql/english/errmsg.sys' had only 480 error messages
So make sure you specify the 64-bit version if you're running a 64-bit version of CentOS, which I am here
OK, so hopefully MySQL is all installed now. Let's start it up
service mysqld start
No problems, hopefully. Though you'll probably get a first start message about securing your installation. Wise words! So lets do it:
Now, follow the instructions carefully. These are my recommendations:
- Set a root password
- Remove anonymous users
- Disallow root login remotely
- Remove test database
- Reload privileges
So, basically, go along with everything that the script suggests
Now let's log in to MySQL and check that everything is as it should be
mysql -uroot -p
Enter the root password that you just set
Now, if you do want to allow root access from your remote workstation, ie where you are right now, do so but with a diffent password, like so:
mysql> CREATE USER 'root'@'192.168.10.3' IDENTIFIED BY 'remoterootpassword';
Replacing 192.168.10.3 with your IP and remoterootpassword with whatever password you want to use
Note that now, you can't log in to MySQL from this session with this username/password combination, but you can log in from a client on your remote machine. Note how the passwords can be different for connecting from the server, and from your workstation? You can have a password per IP if you really want, but personally I tend to only ever allow one valid IP at a time for myself when connecting remotely. If my IP changes then I dial in via SSH, delete that user, and create a new one with the new IP
And that's it. All that's left to do now is to set MySQL server to start when your server reboots. Easy:
mysql> exit; chkconfig --levels 235 mysqld on