Monday, October 22, 2012

How To: LAMP (Linux, Apache, MySQL, PHP) server on Amazon EC2

There are several articles out there outlining the process of getting a LAMP server up and running on Amazon's Elastic Cloud (EC2) service, but most of them seem to be missing some small caveats as well as a couple additional features I wanted my instance to have like FTP access, and VNC access to a GUI as well. Lets get started!

Table of Contents
1. What is this?
2. Prerequisites
3. Create a new server instance
4. Install & Configure Apache, PHP, & MySQL
5. Install & Configure VSFTP
6. Configure Putty to authenticate to your server (optional)
7. Install & Configure VNC
8. Install & Configure Dropbox
9. Resources

1. What is this?
Amazon's EC2 service allows you to host a virtual machine to configure any way you like. You are charged based on your resource consumption at very low rates making this a great way to set up a free hosting account for a small personal site, or even host sites for small business clients if you develop websites professionally. You can choose what operating system you would like to put on your server instance.

2. Amazon EC2 Prerequisites
- If you don't have an Amazon Web Services account you will of course need one. Head over to Amazon Web Services and sign up.
- You'll need java installed to use the web based ssh client to communicate with your instance after it is installed.
- You will probably want a good ftp client to make transferring files to your new web server nice and easy.

3. Create a New Server Instance
There are many ready made LAMP instances available that may reduce your setup time, but this guide is about setting this up exactly how we want it, so we will go with a plain old Ubuntu server and do each step ourselves. Once you've created your instance you will need to find your public DNS address. This will be used several times throughout this process so keep it handy. 

The public DNS address may change under certain circumstances, so it is best to associate an elastic IP address to your instance.

Before going any further you need to know about Amazon's security groups or you will not be able to connect to your server via the web. The EC2 service has an external firewall that will block incoming and outgoing traffic by default unless those ports are opened up. This is done using security groups. Create a new security group and open up the following ports:

20, 21, 22, 80, 9000, 50000 - 51000

This is what my security group looks like:

You will also need to create a Key Pair. This will be used for authentication and is required. From the EC2 management console, click key pairs on the left, and click 'create key pair'. You will need to save the generated .pem file on your computer in a place you will not lose it. This same file will be used for every instance you create (If you lose it you can always generate a new key pair).

Now that we have the security groups and the key pair taken care of, go back to 'instances', right click on your instance and choose 'connect'. Make sure your username is set to 'ubuntu' and click 'Launch SSH Client. Once we have a shell prompt, the first thing we want to do is update the packages installed that may be outdated. To do this, simply type:

sudo aptitude update && sudo aptitude dist-upgrade
Now we need to reboot the server before moving forward with installing our web server components:

sudo reboot
4. Install & Configure Apache, PHP, & MySQL

To Install, execute the following command from the shell:

sudo aptitude install apache2 php5-mysql libapache2-mod-php5 mysql-server
Note: During the install, you will be asked for a mysql password. KEEP TRACK of this password, you will need it later when we install PHPMyAdmin for easy mysql administration.

Once these packages are installed, open a browser and go to your instance address (you can use either the public DNS address, or an IP address if you have assigned one)
Ex:
http://ec2-54-245-13-223.us-west-2.compute.amazonaws.com -OR- http://54.245.80.236

If all is right in the world you will see "It Works!" in your browser indicating our web server is now up and running. 

If you'd like to test PHP, using your favorite text editor, create a new file called test.php. I'm using nano.

sudo nano /var/www/test.php
Type this into the file:

<?php phpinfo(); ?>
Press control+x, press Y when prompted to save and click press enter.

Note: If you receive an error saying you cannot save the file you will need to set the permissions on the var/www/ directory which is explained a bit later in this tutorial (FTP section).

Once you have your test.php file saved, just navigate to the php test page in your browser. Ex: http://54.245.80.236/test.php . You should see a php info page detailing the PHP configuration.

Now we're ready to install PHPMyAdmin which we will use to easily administer MySQL databases.

sudo apt-get install phpmyadmin
At this point it's a good idea to turn on the firewall to harden security a bit. Ubuntu comes with an 'uncomplicated firewall' that can be toggled on and off very easily. Lets turn it on:

sudo ufw enable
Now that firewall is on open up ports 22 and 80. If you want to install FTP you'll also need exceptions for 20, 21, 51000, and 5000. If you're going to enable VNC then you should also allow port 9000. The last two ports can actually be in anything you want so long as it isn't interfering with any other services. These ports are used for passive FTP configuration which we will be using in this tutorial). execute these commands to make your firewall exceptions:

sudo ufw allow 22
sudo ufw allow 80
sudo ufw allow 20
sudo ufw allow 21
sudo ufw allow 9000
sudo ufw allow proto tcp to any port 50000:51000
If you'd like more details on the uncomplicated firewall see the Ubuntu guide on the matter: https://help.ubuntu.com/9.10/serverguide/C/firewall.html

5. Install & Configure VSFTP
You can do this with other ftp servers but the commands below will differ of course. I chose to use vsftpd (or the Very Secure FTP Daemon).

First, we install the package:

sudo apt-get install vsftpd
Now there are several changes we need to make to the configuration file to get this working correctly with amazon's EC2.

First, we need to edit /etc/vsftpd.conf and set some variables.


sudo nano etc/vsftpd.conf
 You'll be looking at a list of configuration settings for vsftpd. We need to turn on a couple that exist and add some others that do now. Find the local_enable and write_enable settings and turn them on by uncommenting them (remove the # at the beginning of the line).

local_enable=YES
write_enable=YES
Add these settings to the bottom of the file. (Again if you don't know your server's IP address you can find it by right clicking your instance in EC2 and choosing connect):


pasv_max_port=51000
pasv_min_port=50000
port_enable=YES
pasv_enable=YES
pasv_address=ip.address.of.server
local_root=/var/www
Now restart vsftpd:

sudo /etc/init.d/vsftpd restart 
You can also use (or just "sudo service vsftpd restart" if you have it configured to run as a service already)

Now we need to create a user to use for logging in via ftp:


sudo adduser YOUR_USER_NAME
Follow the prompts and that's it for creating a new user. But now we need to give the new user permissions to write to the www directory:

sudo chown -R USERNAME /var/www
sudo chmod -R 777 /var/www
From here I went ahead and rebooted for good measure although it may not be necessary. Now launch up your FTP client (I'm using FileZilla) and make sure you can connect, upload files, and overwrite files.

6. Configure Putty to Authenticate on EC2
This process entails using puttygen to import your .pem file from your keypair we set up earlies, and converting to a putty key file. There are also a couple settings you want to change such as the username to use (ubuntu). This is pretty well covered elsewhere so I'll just provide the link here. Just keep in mind I was unable to use Amazon's DNS name for my server, but it worked for me using the elastic IP instead:
Putty connect instructions (must use elastic ip not host name!).

One other helpful tip I found was to make sure and set a root password. After setting up putty I was able to log in as my new user automatically with no problem, however I couldn't run any privileged commands because it would prompt me for a password. The simple fix is to go back to the web based client where you already have proper privileges and run this command to set your root user password:


sudo passwd root
7. Install & Configure VNC
As with most cloud hosts, Amazon's Elastic Compute Cloud (Amazon EC2) offers only Secure Shell (SSH) access by default to Linux cloud servers. But if you aren't a command-line fan or your application requires a GUI, you can set up remote desktop access to most Linux cloud servers.

First Install the gnome desktop manager:


sudo apt-get install gnome-core
Next install the VNC server itself:

sudo apt-get install vnc4server
Now we set a password by simply typing:

 vncserver 
The password cannot be longer than 8 characters. Once the password is set, we want to stop the server:

 vncserver -kill:1
Next, configure the VNC xstartup file so you'll see the desktop when connecting via VNC. Enter nano .vnc/xstartup.

Edit the file until it looks like this:

#!/bin/sh
# Uncomment the following two lines for normal desktop:
unset SESSION_MANAGER
#exec /etc/X11/xinit/xinitrc
gnome-session --session=gnome-classic &

[ -x /etc/vnc/xstartup ] && exec /etc/vnc/xstartup
[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources
xsetroot -solid grey
vncconfig -iconic &
#x-terminal-emulator -geometry 1280x1024+10+10 -ls -title "$VNCDESKTOP Desktop" & 
#x-window-manager &
 Save the file and exit. Start the VNC server back up:

 vncserver -geometry 1024x600
Now go ahead and try to connect using you favorite VNC client such as Tight VNC. In the remote host field you will need to add a :1 like this:

Now we need to configure vncserver to start every time the EC2 instance boots up. We need to add an entry in the init.d folder. If you're unfamiliar, the etc/init.d directory is where Linux stores various start / stop scripts for services. We will be adding one to start the vncserver and use the .conf file we just created.

sudo touch /etc/init.d/vncserver
sudo chmod +x /etc/init.d/vncserver
sudo nano /etc/init.d/vncserver
Paste the following code into our new the init.d script. Notice on line 8 our default username 'ubuntu' is there. If you're using a different username this will need to be changed.

#!/bin/bash
### BEGIN INIT INFO
# Provides: vncserver Required-Start: networking Default-Start: S 
# Default-Stop: 0 6
### END INIT INFO
PATH="$PATH:/usr/X11R6/bin/"
# The Username:Group that will run VNC
export USER="ubuntu"
#${RUNAS}
# The display that VNC will use
DISPLAY="1"
# Color depth (between 8 and 32)
DEPTH="16"
# The Desktop geometry to use. GEOMETRY="x" 
#GEOMETRY="800x600"
GEOMETRY="1024x768"
#GEOMETRY="1280x1024"
# The name that the VNC Desktop will have.
NAME="my-vnc-server" 

OPTIONS="-name ${NAME} -depth ${DEPTH} -geometry ${GEOMETRY} :${DISPLAY}" 

. /lib/lsb/init-functions 

case "$1" in 
start) 
log_action_begin_msg "Starting vncserver for user '${USER}' on localhost:${DISPLAY}" 
su ${USER} -c "/usr/bin/vncserver ${OPTIONS}" 
;; 

stop) 
log_action_begin_msg "Stoping vncserver for user '${USER}' on localhost:${DISPLAY}" 
su ${USER} -c "/usr/bin/vncserver -kill :${DISPLAY}"
;; 

restart) 
$0 stop 
$0 start 
;; 
esac
exit 0
Run the vncserver command once more.

vncserver

And finally, we need to run this command to add our init.d script to system startup:

sudo update-rc.d vncserver defaults 99
Now restart the service:

sudo service vncserver restart
8. Install & Configure Dropbox
The goal here is to allow me to edit files right in my dropbox from my home PC or mobile phone and have those changes automatically sync to my server's var/www directory making the changes live without the need for manually transferring files via FTP. This has also been pretty well documented so I'll simply share a link if you're interested in taking this additional step.
Set up DropBox Selective Sync on Ubuntu EC2

9. Resources
Putty connect instructions (must use elastic ip not host name!):