Preparing a new LAMP server on Rackspace Cloud

I've been looking for a new hosting provider for some time now and have often been tempted by (and equally cynical of) the hype surrounding cloud computing, but about 6 months ago or so finally took the plunge and signed up for a Rackspace Cloud account and haven't looked back since. This is a quick guide to get your own server up and running with a bare bones LAMP setup running on Ubuntu 10.04 LTS. Other Ubuntu distributions should be fairly similar, as will any Debian based distribution.

Get started by creating your server. The base spec will be more than adequate for a simple LAMP server with light traffic, but by all means choose the specification you're most comfortable with. Once your server has been created, simply ssh into it as root using the IP address and password Rackspace will have sent you when your server is ready to be accessed.

A Note about Locales

The most recent cloud servers I've created have not come with the default locale generated (older ones did). If you receive the following error when running any of the following commands:

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
	LANGUAGE = (unset),
	LC_ALL = (unset),
	LANG = "en_GB.UTF-8"
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").

Then this is easily fixed by running:

root@pd01:~# locale-gen en_GB.UTF-8

Just make sure that en_GB.UTF-8 matches up with your LANG value.

Basic SSH Security

First things first: let's create a new user so we can disable root login via SSH. If you're on a debian flavoured distro (which includes Ubuntu) I'd recommend you use adduser, which is a slightly friendlier wrapper for useradd. It'll prompt you for a password and allow you to enter several lines of optional information about the new user - personally I just enter a password and skip the rest of the details:

root@pd01:~# adduser nick

The first thing we want to do with our new user is give them sudo privileges so we can quickly set about locking down root access to the machine. To do this, we need to run the special visudo command:

root@pd01:~# visudo

Give your new user sudo privileges by adding the relevant line underneath the equivalent line for the root user:

# User privilege specification
root    ALL=(ALL) ALL
nick    ALL=(ALL) ALL

Logout, then log back in as your user. Verify that you're in the sudoers group by running a command prefixed with 'sudo':

nick@pd01:~$ sudo ls -lah
[sudo] password for nick:
total 24K
drwxr-xr-x 3 nick nick 4.0K 2011-08-03 09:20 .
drwxr-xr-x 4 root root 4.0K 2011-08-03 09:16 ..
-rw-r--r-- 1 nick nick  220 2011-08-03 09:14 .bash_logout
-rw-r--r-- 1 nick nick 3.1K 2011-08-03 09:14 .bashrc
drwxr-xr-x 2 nick nick 4.0K 2011-08-03 09:20 .cache
-rw-r--r-- 1 nick nick  675 2011-08-03 09:14 .profile

If the above doesn't work then log back in as root and check your sudoers file against the example above.

Now we have a user with sudo rights we can move on to tightening up SSH access. Edit /etc/ssh/sshd_config (use sudo to edit it otherwise it will be read-only) and look for the line PermitRootLogin yes - it should be around line 26 of the file. Simply change the value to no and save file. We'll tighten this further in a minute by also limiting SSH access to private/public key based logins, but first we need to add a public key for our newly created user. There are a huge variety of ways you can add a public key to your server, the easiest of which by running ssh-copy-id myuser@myhostname on the machine(s) from which you wish to authorise to access your server, though this of course depends on having the command available on your client machine and already having a local private/public key pair (which you can usually generate with ssh-keygen on the client machine). One of the most common pitfalls in setting up key based authentication is incorrect (usually too generous) permissions on either the client or server machine's .ssh/ folder and contents. There are plenty of useful guides written by people with far more expertise available so if you're struggling then see what a Google search turns up, or leave a comment in this post. In the following example, I'm using ssh-copy-id from my local desktop machine, which automatically creates the remote .ssh folder and authorized_keys file on the server with the correct permissions if they don't already exist (which they won't on a clean install):

nick@nick-desktop:~$ ssh-copy-id nick@46.38.162.236
nick@46.38.162.236's password: 
Now try logging into the machine, with "ssh 'nick@46.38.162.236'", and check in:

  ~/.ssh/authorized_keys

to make sure we haven't added extra keys that you weren't expecting.

Once you've added a public key for your user, log in again - if your key has no passphrase you should be logged in to the server immediately, otherwise you will be challenged for your key's passphrase - but the important thing is you should not see the 'Password:' prompt. Now you can disable password login via SSH to prevent brute force attacks altogether. Open /etc/ssh/sshd_config and look for roughly line 50: #PasswordAuthentication yes. Remove the hash at the start of the line and change yes to no. Restart SSH to confirm your changes:

nick@pd01:~$ sudo /etc/init.d/ssh restart
 * Restarting OpenBSD Secure Shell server sshd
   ...done.

Congratulations! You've now secured your server against brute force username/password login attacks. This is of course just a start - but it's a good one.

Putting the AMP in LAMP

Now you've got the basic server set up, let's move on to installing Apache, MySQL and PHP. Enter aptitude: sudo apt-get install xxxx. The following one-liner installs all of the essential PHP, Apache and MySQL executables, drivers and modules. When prompted, enter Y or just hit the return key:

nick@pd01:~$ sudo apt-get install apache2 php5 php5-cli php5-mysql libapache2-mod-php5 mysql-server
[sudo] password for nick:
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
  apache2-mpm-prefork apache2-utils apache2.2-bin apache2.2-common libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap libdbd-mysql-perl libdbi-perl libhtml-template-perl libmysqlclient16
  libnet-daemon-perl libplrpc-perl mysql-client-5.1 mysql-client-core-5.1 mysql-common mysql-server-5.1 mysql-server-core-5.1 php5-common psmisc ssl-cert
Suggested packages:
  www-browser apache2-doc apache2-suexec apache2-suexec-custom ufw php-pear libipc-sharedcache-perl libterm-readkey-perl tinyca mailx php5-suhosin openssl-blacklist
The following NEW packages will be installed:
  apache2 apache2-mpm-prefork apache2-utils apache2.2-bin apache2.2-common libapache2-mod-php5 libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap libdbd-mysql-perl libdbi-perl
  libhtml-template-perl libmysqlclient16 libnet-daemon-perl libplrpc-perl mysql-client-5.1 mysql-client-core-5.1 mysql-common mysql-server mysql-server-5.1 mysql-server-core-5.1 php5-common
  php5-mysql psmisc ssl-cert
0 upgraded, 27 newly installed, 0 to remove and 0 not upgraded.
Need to get 34.3MB of archives.
After this operation, 90.8MB of additional disk space will be used.
Do you want to continue [Y/n]?

At some point you'll be prompted to enter a root password with which you can later access MySQL. You don't have to but I'd strongly suggest you do - and when you do, make sure you remember it! When all the required packages have been installed you should be able to now visit your server's IP address in your web browser and be greeted with the default "It works!" Apache index page. Great!

Configure Apache

At this point requirements can start to diverge wildly. I've gone with the most basic assumptions - that you'll want to run several different domains on the server, and that you'll need to use mod rewrite at some point. Let's run the a2enmod command to see a list of available apache modules (some of which are already enabled):

nick@pd01:~$ sudo a2enmod
Your choices are: actions alias asis auth_basic auth_digest authn_alias authn_anon authn_dbd authn_dbm authn_default authn_file authnz_ldap authz_dbm authz_default authz_groupfile authz_host authz_owner authz_user autoindex cache cern_meta cgi cgid charset_lite dav dav_fs dav_lock dbd deflate dir disk_cache dump_io env expires ext_filter file_cache filter headers ident imagemap include info ldap log_forensic mem_cache mime mime_magic negotiation php5 proxy proxy_ajp proxy_balancer proxy_connect proxy_ftp proxy_http proxy_scgi reqtimeout rewrite setenvif speling ssl status substitute suexec unique_id userdir usertrack version vhost_alias
Which module(s) do you want to enable (wildcards ok)?
vhost_alias rewrite ssl
Enabling module vhost_alias.
Enabling module rewrite.
Enabling module ssl.
See /usr/share/doc/apache2.2-common/README.Debian.gz on how to configure SSL and create self-signed certificates.
Run '/etc/init.d/apache2 restart' to activate new configuration!

Configure PHP

We'll only perform a very small amount of PHP configuration as again, usage requirements will vary wildly. The following line will install some common PHP extensions which a lot of third party code depends on and install APC - a caching mechanism which will cache your PHP scripts without any explicit invocation:

nick@pd01:~$ sudo apt-get install php5-mcrypt php5-curl php-apc

While we're at it, let's edit (using sudo) /etc/php5/apache2/php.ini and turn the value for expose_php to Off (it's on by default). This is a very quick measure which slightly reduces your server's exposure - it is not going to secure your server but prevents trivial exposure of the fact you're running PHP which is worthwhile for the effort it takes.

Set up your first VirtualHost

Almost done - now all we need is a site to serve some content on! The convention when declaring VirtualHosts on an Ubuntu system is to simply place config file snippets in /etc/apache2/sites-available/ and then use the helper tool a2ensite (and a2dissite) to enable / disable 'sites' at will. By convention, each config file only declares one VirtualHost (therefore one 'site'), though of course there's nothing to stop you declaring multiple VirtualHosts in one file. You'll notice that there are already two sites in the sites-available/ directory, which are default and default-ssl - which are your standard fallback VirtualHosts - if you're curious then it's worth examining default, noting its DocumentRoot and then having a look at the contents of /var/www/index.html - which explains the default "It Works!" message you saw earlier.

Let's create a very simple VirtualHost of our own. Change into /etc/apache2/sites-available/ and create a blank new file of your choice. The name of the file is not particularly important - but the more VirtualHosts you have the more you might want to come up with a standard convention of your own:

nick@pd01:/etc/apache2/sites-available$ sudo touch mydomain.com

Edit that file, and add pretty much the most basic VirtualHost configuration possible to it. Be sure to replace mydomain.com with a valid domain you've configured to point at your new server, or if you simply want to test things out then be sure to add your server's IP address for mydomain.com to your local /etc/hosts file:

<VirtualHost *:80>
    ServerName mydomain.com
    ServerAlias www.mydomain.com
    DocumentRoot /var/www/mydomain.com
</VirtualHost>

This simple snippet is instructing Apache to use any code / html in /var/www/mydomain.com to handle any incoming requests on port 80 with a host name of mydomain.com (or www.mydomain.com). The ServerAlias line is important if you're configuring a normal site which you want to work both with and without the www prefix. You can only specify one ServerName but many ServerAlias strings.

Naturally, we now need to create the corresponding directory. Again by convention your files will be located under /var/www - stick with this unless you know of a good reason not to as all subfolders inherit certain default Apache settings which are useful to have. Once created, let's add an index.html file to greet visitors to our new site:

nick@pd01:~$ sudo sh -c "echo '<h1>Hello MyDomain.com</h1>' > /var/www/mydomain.com/index.html"

We're almost there - we just need to enable the new VirtualHost...

nick@pd01:~$ sudo a2ensite mydomain.com

... and reload Apache's configuration files:

nick@pd01:~$ sudo /etc/init.d/apache2 reload

Providing you didn't get any errors upon reloading Apache, you should now be able to navigate to http://mydomain.com and be greeted with your fantastic new site. Note that this configuration is extremely simple but is also extremely limited - far more useful information is available on the Apache documentation website. While we're at it, let's create an index.php file to check our PHP installation is running as expected too:

nick@pd01:~$ sudo sh -c "echo '<?php phpinfo(); >' ?> /var/www/mydomain.com/index.php"

You'll notice that going to http://mydomain.com serves the index.html rather than index.php, but you can view your PHP file by visiting http://mydomain.com/index.php. The default file which Apache chooses to serve is easily configured by changing the DirectoryIndex directive - but that's a topic for more advanced VirtualHost discussion.

Wrapping Up

By now you've got a fully functional LAMP stack - although we haven't really touched much upon the 'M' or 'P' parts of that in this guide - watch out for another post about those two soon. This set up is also just the beginning; server administration is a huge area and this guide is not intended to be comprehensive - but just enough to get you going. Further posts will discuss PHP, MySQL, setting up an MTA (to send emails from your site), further website security, securing your site with SSL, and a lot more.

Until then...

Related Articles

Comments

Steve Parker
Thank you for this! You saved me a LOT of time by having everything in one place. I appreciate the explanations of each step too. They made it much easier for me to deviate when I wanted to.

Comments are now closed.