Contents

[edit] This tutorial

This tutorial represents a combination of many other tutorials on this topic. I combined them specifically for my situation.

I read multiple different tutorials on each topic that this tutorial covers and I made a good effort to select the elements that included best practices and the cleanest configuration.

Use this tutorial if any of these statements apply to you:

  • You have a decent amount of experience using the linux command line
  • You are working on Linode or some other Virtual Private Server (VPS) or just using your own machine
  • You want to install Ubuntu 8.04 Hardy Heron LTS (server edition -- NOT the desktop edition)
  • You need Linux, Apache, MySQL and PHP
  • You have one IP address associated with your VPS (for a site with multiple IP addresses, see the LAMP tutorial at the Linode Library
  • You want to configure your system to host multiple sites/domains
  • You want to relay all email sent from your server through you Google Apps for Domains account
  • You are trying to set up a production-quality server
  • You want to have a test site and a live site on the same server
  • You are deploying a Drupal 6 site
  • You want to have email sent from your domain to be routed through Google Apps
  • You need to configure an SSL certificate to have secure sections of your site

There are some example values used throughout the tutorial that you will need to replace with values for your own server:

  • IP Address: 12.34.56.78 - replace this with the IP address of your Linode VPS. This can be found on the Network page within the Linode Manager.
  • Domain name: example.org - replace this with the domain or subdomain of the site you are currently setting up.
  • Test site subdomain: staging.example.org - It is good practice to have a test site to deploy your site to before moving it over to it's final location on the primary domain. This tutorial will approach the server setup assuming you are working with staging.example.org to begin with and moving to example.org later.
  • Hostname: onefish - This should be a unique name that has nothing to do with any of your subdomains, your company or your domain name. It just becomes the "name" of your computer. By itself, it doesn't effect how the outside world sees the server. It is just an internal identified. Pick something silly or random.
  • Fully qualified domain name: onefish.example.org - This should be a unique subdomain that becomes the external address for your server, but not the websites hosted on your server. When you are SSH-ing into the server, you could choose to access it from this address. It is easiest to just pick a subdomain that matches the hostname you just chose.
  • Username: jeremy - replace this with your preferred name or username.
  • SSH Port: 22001 - replace this with a randomly number that is relatively high (Between 20000-32000)

[edit] Programs to use

I will be using Windows XP as client computer, but I will mention the Mac OS X and Linux alternatives when possible.

When logging into the server over SSH on Windows, I will use PuTTY. (Max OS X users have access to the Terminal application.) To copy text from putty, just highlight it and it will be on your clipboard. To paste text, just right click and it will be inserted wherever your cursor is.

When uploading files to the server, I use WinSCP. On OS X, you can use Cyberduck.

When instructed to edit files over SSH, you can use vi, nano or the editor of your choice. Nano lists the commands at the bottom of the screen. You can edit a file with nano using:

nano /foo/bar/filename/here

... Or after you have disabled the root account, you must use:

sudo nano /foor/bar/filename/here

When instructed to "find and edit the following line(s)", make sure you search for whatever is at the begging of the line and make it match the entire line shown in the tutorial. You can search in nano using Ctrl + W

[edit] Passwords

Whenever I need to generate a secure password that I won't need to type in often (SSH, MySQL accounts, etc) I use the following site to generate a password: Perfect Passwords

The three unique strings can be mixed and matched for added security. I tend to use HEX strings (the top box) for passwords that I have to enter in on the command line because sometimes characters like ! and * can give unexpected results.

[edit] Installing a Linux Distribution on Linode

Note: Linode's detailed guide has the same instructions that are in this section, but it also includes screenshots.
  1. Choose server location
  2. Go to the Distro Wizard
  3. Select Ubuntu 8.04 LTS (not the 64 bit version)
  4. Leave the disk size as is. It will take up the entire disk
  5. Leave the swap space at 256 MB unless you have reason to bump to up. Do not let it exceed 512 MB.
  6. Enter a root password
  7. You will be taken to the dashboard. Next to your My Ubuntu 8.04 LTS Profile configuration profile, click the Boot.
  8. Refresh the dashboard until the Host Job Queue says No pending jobs.
  9. Log into the server using the terminal or PuTTY.

[edit] Basic Ubuntu Setup

Update your repositories and upgrade Ubuntu to the most recent security release

apt-get update
apt-get upgrade --show-upgraded

[edit] Timezone and System Clock

Make sure to configure the timezone to match your timezone or the timezone that most of your users will be in. If you're unsure of what timezone to use, I would suggest setting it to UTC as this could save you from some headaches later down the road.

dpkg-reconfigure tzdata

While we're dealing with time, let's make sure our system clock never drifts. Since your server could be up for months at a time without a restart, it can drift from the hardware clock. The cleanest way make sure this doesn't happen is to install NTP.

apt-get install ntp

This daemon will constantly adjust our system to match the time on verious NTP servers. You can choose your list of servers from the NTP pool. Since my server is in the United States, I put the following servers into the NTP configuration file:

File: /etc/ntp.conf

server ntp.ubuntu.com
server 0.north-america.pool.ntp.org
server 1.north-america.pool.ntp.org
server 2.north-america.pool.ntp.org
server 3.north-america.pool.ntp.org

Ubuntu's server guide has more information on NTP.

[edit] Hostname and Hosts

Now give the system a hostname. An explanation of hostnames was given in the introduction to this tutorial. This is an internal identifier and doesn't effect how the machine talks to the rest of the internet. You could use the hostname of onefish, but it is more common to use the fully qualified domain name (FQDN):

echo "onefish.example.org" > /etc/hostname
hostname -F /etc/hostname

Now we need to tell our Linode to associate with a the public IP address. Edit the first section of the /etc/hosts file to have. Make sure you replace 12.34.56.78 with the IP address of your Linode.

File: /etc/hosts

127.0.0.1       localhost
12.34.56.78     onefish.example.org     onefish

[edit] Various utilities

Now we need to set the default shell to bash instead of dash.

ln -sf /bin/bash /bin/sh

Now install a few common utilities that you'll need to get eventually:

apt-get install wget rsync zip unzip

If there is ever a chance that you will have to build a program/utility from scratch on the server, make sure you run:

apt-get install build-essential

[edit] Static IP Address

By default, your system will be configured to use DHCP to determine its IP address. Since it will only ever have one IP address, you should tell it to just use that for outbound connections.

The Linode Library has a great tutorial on configuring a static IP address, so I will leave the explanation to them. I am just going to show you what you need to do, so refer to that tutorial if you'd like more of an explanation. If you have private IP address aliases, then follow their tutorial instead of this section. If you don't know what that is, then follow this section.

First, go to the Linode Manager and click on the Network tab. Take note of all the information there. Let's pretend our information looks like this:

eth0: 12.34.56.78 ( staging.example.org )
Gateways: 12.34.56.1
Netmask: 255.255.255.0

Now we want to use this information to specify our static IP. Place the information above in the /etc/network/interfaces file to make your IP static.

File: /etc/network/interfaces

# The loopback interface
auto lo
iface lo inet loopback

# This line ensures that the interface will be brought up during boot.
auto eth0

# eth0 - This is the main IP address that will be used for most outbound connections.
# The address, netmask and gateway are all necessary.
iface eth0 inet static
 address 12.34.56.78
 netmask 255.255.255.0
 gateway 12.34.56.1

[edit] Users and SSH

It is a security risk to always log in through the root account. The best practice is to create a separate account for yourself (and other users who might need to access the server).

Add an account for yourself (and any other users)

adduser jeremy
usermod -G staff,admin jeremy

Let's do some configuration so that random users won't be able to attempt to SSH into our root account on port 22.

Find and edit each of the following lines inside the /etc/ssh/sshd_config file:

Port 22001
Protocol 2
PermitRootLogin no
X11Forwarding no

The port number can be 22001 or anything other than port 22. The port must be something high because lower range ports are reserved for certain applications and protocols. Just make sure you don't make it too hard to remember, because when you are SSH-ing in from PuTTY or the terminal, you will need to specify the port.

Also, append these two lines to the end of the file. Be sure to replace jeremy with the username you just made for yourself.

UseDNS no
AllowUsers jeremy

Now we need to restart the SSH daemon for these changes to take effect.

/etc/init.d/ssh reload

Don't close the current SSH session in case you accidently locked yourself out. Simply open a new session and login with the account you just created. To do this through PuTTY, just change the port to the one you assigned above and use the same IP address that you used before. To do this from the Mac OS X terminal, run the follwing command (make sure to change the port, username and IP address to match what you have configured so far):

ssh -p 220015 [email protected]

You will no loner be able to the root account. From now on, if you want to run a command as though you were the root account, you will have to prepend sudo to the command. For example:

sudo apt-get install [some package here]

[edit] Configuring your account

Now that we're logged into our personal accounts, let's edit the ~/.bashrc file and add some shortcut commands to make our lives a bit easier. Scroll to the bottom of the file and add:

alias free="free -m"
alias a2r="sudo apache2ctl restart"

To get bash to recognize these new aliases, run:

source ~/.bashrc

Now we can use the free command to see how much RAM is being used. Restarting Apache is a very common task, so we can now do that quickly with the a2r (think: "apache 2 reload") command. This will gracefully restart apache without disconnected any users that are in the middle of downloading a file (whether it is big or tiny).

[edit] Login without a password (optional)

Note: This section is optional.

If you want to be able to log into your Linode without giving your password every time (and you're confident that no one will gain access to your computer), then you can follow the steps in this section.

GitHub has a good SSH key tutorial although it is specific to their system, not a Linode VPS.

To do this on Windows with PuTTY, start by running PuTTYgen (it should be in the start menu under PuTTY).

  1. Click Generate
  2. Move the mouse around randomly
  3. Enter your email address for the comment
  4. Leave the passphrase fields blank
  5. Click Save private key and save it in your user folder somewhere
  6. Copy paste the public key to the clipboard

Go back to the SSH session you have open and execute the following commands:

mkdir ~/.ssh
nano ~/.ssh/authorized_keys

Now paste in the public key that should still be on your clipboard. Make sure that the key is all on one line at the top of the file. When you copy paste it from PuTTYgen, it will be on three lines. It should look something like this:

ssh-rsa AAAAB3Nza[......]qILFC32xQ== [email protected]


Save and exit nano.

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

Now we can edit our SSH config file so that password authentication is not allowed at all. Only do this if you're sure that all users are going to login using SSH keys in the future. If you're the only user for this server and you've made it this far, then you're probably safe to continue.

Edit the /etc/ssh/sshd_config file again. You must now use sudo to edit the file.

sudo nano /etc/ssh/sshd_config

Find the following line and change it from yes to no (Note: Make sure you remove the # infront of the line so that it is no longer commented out):

PasswordAuthentication no

Save the file and exit nano. Now restart the SSH daemon:

sudo /etc/init.d/ssh reload

Go ahead and log out of this SSH session. You should still have the root SSH session open in the background as a backup incase something goes wrong.

To log back in using PuTTY, you now need to specify the private key that you saved somewhere in your user folder. To do this, follow these steps:

  1. Open PuTTY
  2. Enter the IP address of your server and the port you configured
  3. In the left menu go to Connection > SSH > Auth
  4. For Private key file for authentication, select Browse and find the private key file you saved to your user folder.
  5. Under Connection > Data, enter your username as the Auto-login username
  6. Got back to Session (in the left sidebar) and save this session

Note: When using SFTP to transfer files later in this tutorial, make sure that you set the custom port and use the private key for authentication.

[edit] Apache

Now it's time for us to set up the A in LAMP: The Apache server. The information in this section was gathered from many places, but a simple version of these steps can be found at the Linode library Ubuntu 8.04 LAMP tutorial.

[edit] Installing Apache

First install the server and a few additional packages

sudo apt-get install apache2 apache2-doc apache2-mpm-prefork apache2-utils libexpat1 ssl-cert

[edit] Virtual Hosts

Now we need to set up virtual hosts for each website we are going to host on this server. Even if you think you are only going to have one website, it is good to keep it in it's own folder incase you change your mind later.

First, make sure you disable the default site. Run this command:

sudo a2dissite default

No edit the base config file to tell it what virtual hosts to respond to. We'll use separate host config files for each site/subdomain we set up, but this directive needs to go into the base config file before we include each of those sites.

Find the Include /etc/apache2/sites-enabled/ at the bottom of the following file. Before that line, put the following line:

File: /etc/apache2/apach2.conf

NameVirtualHost *:80

Add the following to the file /etc/apache2/sites-available/staging.example.org (as always, replace staging.example.org with yoru site or subdomain.yoursite.com). The name you specify here will be the default that apache uses, so if you have your DNS set up to use wilcard subdomains, the files in DocumentRoot will be served if the user types in a random, non-existent subdomain. Copy this stanza of code into the file for each site (domain or subdomain) that you want to configure:

File: /etc/apache2/sites-available/staging.example.org

<VirtualHost staging.example.org:80>
     ServerAdmin [email protected]
     ServerName staging.example.org
     DocumentRoot /var/www/staging.example.org/public_html/
     ErrorLog /var/www/staging.example.org/logs/error.log
     CustomLog /var/www/staging.example.org/logs/access.log combined
     <Directory /var/www/staging.example.org/public_html/>
          Options Indexes FollowSymLinks MultiViews
          AllowOverride All
          Order allow,deny
          allow from all
     </Directory>
</VirtualHost>

We must make the appropriate folders for the configuration we just specified:

sudo mkdir -p /var/www/staging.example.org/public_html
sudo mkdir -p /var/www/staging.example.org/logs

Now we can enable the site using the nifty a2ensite command:

sudo a2ensite staging.example.org

Before we can use the site, we must restart apache. We can use the alias we made earlier.

a2r

Anytime you use a2ensite or a2dissite to enable or disable a site, you must restart apache.

Assuming you've configured your DNS to point to Linode's IP address, you should now be able to access your site from the domain you specified.

[edit] Testing Apache

Let's put the server through a very basic test.

Create a file at /var/www/staging.example.org/public_html/index.php and enter the following text:

Hello, world!!

Now try to visit your site at the specified domain (http://staging.example.org/ in my case).

[edit] Apache Modules

First let's disable the modules we don't need (assuming we're running a PHP-centered site):

sudo a2dismod cgi
sudo a2dismod autoindex

Now we want to enable some modules to give our server some spice. Run the following commands:

sudo a2enmod deflate
sudo a2enmod expires
sudo a2enmod cache
sudo a2enmod rewrite 
sudo a2enmod include

The deflate modules helps us send compressed files to the user. To put deflate and expires to use, we must edit the following file:

File: /etc/apache2/apache2.conf (This is the file where you should put your system wide Apache configuration settings. See Linode Library's notes on Apache configuration options)

# Gzip html, css, js, etc.
AddOutputFilterByType DEFLATE text/html text/css text/plain text/xml applicamailtion/x-javascript application/json
# Set expires headers on html, css, js, etc.
<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresByType text/html "access plus 1 seconds"
  ExpiresByType image/gif "access plus 1 month"
  ExpiresByType image/jpeg "access plus 1 month"
  ExpiresByType image/png "access plus 1 month"
  ExpiresByType text/css "access plus 1 week"
  ExpiresByType text/javascript "access plus 1 month"
  ExpiresByType application/x-javascript "access plus 1 month"
</IfModule>
# Set ETags
FileETag MTime Size

As always, we need to restart Apache after changing the configuration or enabling/disabling modules:

a2r

See how useful our alias command is?

[edit] MySQL

Now we're on to the M in LAMP: MySQL. It is one of the most popular database systems in use today.

[edit] Installing MySQL

As usual, we're going to use the apt-get command to retrieve packages from the Ubuntu repositories:

sudo apt-get install mysql-server mysql-client

During the installation process, your will be asked to enter a password. This will be the password for the root database user. This can be changed later, but it needs to be secure.

We aren't going to change any of the oonfiguration options, but if you want to, the config file is located at /etc/mysql/my.conf.

[edit] Create a database

Whether you are creating your own application or installing a platform like Wordpress or Drupal, you will need at least one database to get things up and running.

First, log in to mysql using the command:

mysql -u root -p

Enter the password you selected during the installation process.

We are now in the mysql console. Let's create a database and user that only has access to that database:

CREATE DATABASE 'swarm';
GRANT ALL ON swarm.* TO 'queen'@localhost IDENTIFIED BY 'honey';
quit

This creates a database named swarm that can only be connected to locally (in other words, no outside entities can try to connect to it) with the username queen and the password honey. At some point, you will need to enter this name, username, password combo into your code to connect to the database. Having a user for the database is more secure than enter the root password into the code (in case the files are ever compromised).

[edit] PHP

On to the P in LAMP: PHP.

[edit] Installing PHP

To install PHP and all the necessary modules, run this command:

apt-get install libapache2-mod-php5 php5 php5-common \
  php5-curl php5-dev php5-gd php5-idn php-pear php5-imagick \
  php5-imap php5-mcrypt php5-memcache php5-mhash php5-ming \
  php5-pspell php5-recode php5-snmp php5-sqlite php5-suhosin \
  php5-tidy php5-xcache php5-xmlrpc php5-xsl php5-mysql

It's as easy at that! Now let's test it.

Run this command to create a test PHP file (make sure to change the directory to the site you configured):

File: /var/www/staging.example.org/info.php

<?php phpinfo(); ?>

You should now be able to go to http://staging.example.org/info.php and see a few pages worth of information that tells you about your PHP configuration on this server. You might want to delete the file afterwards so no one has access to the details about your server.

sudo rm /var/www/staging.example.org/info.php

[edit] Configuring PHP (optional)

Everyone has different needs and will need to configure PHP differently. Since I am using Drupal, I am going to increase maximum RAM that a script can use.

Find these lines and make sure they match what you see below. You can use Ctrl + w in nano to find the beginning of each line.

File: /etc/php5/apache2/php.ini

error_reporting = E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR
display_errors = Off
log_errors = On
error_log = /var/log/php.log
max_execution_time = 300
memory_limit = 64M
register_globals = Off
upload_max_filesize = 8M

If you're in a development environment, you way want to set display_errors = On so they still come up on the screen, but since this tutorial is geared towards a production environment, we will have them all saved to /var/log/php.log instead.

[edit] Mail (relay through Google Apps)

Many places use Google Apps Standard (free, ad-supported) or Google Apps Business Edition (paid) to manage their incoming and outgoing email. This will give you the same interface as Gmail, but it will use your domain name ([email protected]). This section will assume you're using Google Apps and you also want to be able to send mail from your server. If you want to use this server to send and receive mail, you should investigate Postfix.

First, you need to configure the MX records with your DNS to point to Google's servers. You can find instructions for that on the Gmail support site.

This won't allow you to use the php mail() function to send mail from your scripts. You might need to send mail if you're using WordPress and you want to notify users about a new comment. To be able to send mail, we're going to install a lightweight SMTP server: MSMTP.

What we're going to configure is an SMTP relay. All mail that you server sends will be routed through Google's servers and then Google will send it on it's way. Think of this the same way you think of a Desktop email client (like Thunderbird or Microsoft Outlook). Those programs send the mail to the email host (Google) and Google does the heavy lifting. The same thing will happen with MSMTP.

First, go to Google Apps and create a new account that will control your global email sent from the server. This might be [email protected] or [email protected]. Keep in mind that you will be sending out automated emails from this address and people might reply to them. If you don't want to have to log into this account separately from you primary account, you can go into the Gmail settings and have it forward to one or more accounts. Those people will then be able to respond to any emails that are sent to your default address.

The other benefit of relaying mail through Google's servers is that your email will never be marked as spam by the mail service that receives the email (like Yahoo or AOL) since it is coming from a trusted source.

Now we can install ca-certficiates (which allows us to authenticate with Google's Servers when sending mail) and MSMTP.

sudo apt-get install msmtp msmtp-mta ca-certificates

The ca-certificates will install a bunch of certificates to your /etc/ssl/certs/ directory. Do not confuse these with any SSL certificates that you purchase from a provider. The ca-certificates pack can be thought of as the "client side". They are the same certificates that your browser uses to check if a server has a valid certificate or not.

Now we can configure our global MSMTP settings with our [email protected] username/password details (Be sure to replace [email protected] and PASSWORD with the details for the account you created).

File: /etc/msmtprc

account default
host smtp.gmail.com
port 587
timeout 30
auth on
user [email protected]
password PASSWORD
auto_from off
from [email protected]
maildomain example.org
tls on
tls_starttls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile /var/log/msmtp.log
Note: Using /etc/ssl/certs/ca-certificates instead of <tt>/etc/ssl/certs/Thawte_Premium_Server_CA.pem because when the former is used, there are no errors when running msmtp from the command line. Some tutorials will suggest you download certificates from https://www.verisign.com/support/thawte-roots.zip, but this is not necessary in our case because we already installed the ca-certificates package.

Since the file has your password, let's make it readable only by root. And while we're at it, let's create the log file we specified in configuration file.

sudo chmod 600 /etc/msmtprc
sudo touch /var/log/msmtp.log

Now we need to configure PHP to use MSMTP. Find and edit the following line (make sure you remove the semicolon from the beginning of the line so it isn't commented out!):

File: /etc/php5/apache2/php.ini

sendmail_path = /usr/bin/msmtp -t -i

Let's restart apache to make

Now let's send a test email from PHP to our personal email address over the command line to see if things are working. From the command line, run:

sudo php -r "mail('[email protected]', 'Test Email', 'Test email body');"

We have to run the command as "sudo" because only root can read the configuration file that we just made.

If you receive an email, you should be good to go.

Note: If you wanted to have mail sent from multiple personal accounts, you could configure how each user sends mail by placing a configuration file in ~/.msmtprc with their username and password. This section of the tutorial only covers setting up a global email address (which your scripts will use by default).

[edit] Security

[edit] Firewall (closing ports)

I debated between two different firewall programs for this server: arno-iptables-firewall (simple, easy to configure) and vuurmuur (more control, fairly easy to use overall).

I chose arno-iptables-firewall because I wanted to keep things as simple as possible. As always, there is a great Tutorial at Linode Library about how to configure it.

Before we begin, let's determine what ports we want to leave open. Here is a great list of common ports to choose from.

Here are the ports I went with: 80 (HTTP), 443 (HTTPS), 9786 (our custom SSH port)

If you are setting up your own email server instead of relaying mail through Google Apps, then you will need to add those ports.

IMPORTANT: If you configured a custom SSH port earlier in this tutorial, make sure to specify that port and not port 22. If you don't open up the port that you use to SSH into, you won't be able to log back in. You can use Lish to access your Linode if you do accidentally lock yourself out. If you did not specify a custom SSH port, then go ahead and include port 22 in your list.

DO NOT enable port 3306 for MySQL unless you're sure you need to be able to access it from other servers. Also DO NOT enable port 21 for FTP unless you absolutely have to. Instead, use the SFTP (FTP over SSH) on the custom port you chose at the beginning of this tutorial (22001 for example) and authenticate either with your password or the public/private key that you set up earlier.

Now run this command:

sudo apt-get install arno-iptables-firewall

This will take you into the "graphical" user interface.

Answer each question as specified below:

  1. Do you want to manage firewall setup with debconf? Yes
  2. (general information screen): Ok
  3. External network interfaces: eth0
  4. Open external TCP-ports: 80 443 9786
  5. Open external UDP-ports: [leave blank]
  6. Internal network interfaces: [leave blank]
  7. Should the firewall be restarted now? Yes
  8. Should the firewall be restarted now? Yes (yeah... it asks twice)

If you ever need to re-configure your firewall, you can run the command:

sudo dpkg-reconfigure arno-iptables-firewall

If you want more detailed control over the firewall setup, the configuration file is located at /etc/arno-iptables-firewall/firewall.conf

[edit] fail2ban (blocking brute force attacks)

fail2ban is a program that will detect people trying to log in many times in a row and it will block them for a specified amount of time. It does this by keeping an eye on all of the logs for each of the services (SSH, HTTP, FTP, mail) and if it sees multiple failed logins, it will ban that IP address for a specified amount of time.

Let's start by installing fail2ban:

sudo apt-get install fail2ban

Now we need to create a configuration file. While /etc/fail2ban/jail.conf has the deafults, we don't want to add our own configuration file there. That's what jail.local is for. You can learn more about fail2ban configuration files at howtoforge.

Here's what your custom configuration file will look like to secure SSH and Apache password'ed folders.

File: /etc/fail2ban/jail.local

[DEFAULT]

# "ignoreip" can be an IP address, a CIDR mask or a DNS host
ignoreip = 127.0.0.1
bantime  = 1800
maxretry = 3

# "backend" specifies the backend used to get files modification. Available
# options are "gamin", "polling" and "auto".
# yoh: For some reason Debian shipped python-gamin didn't work as expected
#      This issue left ToDo, so polling is default backend for now
backend = polling

#
# Destination email address used solely for the interpolations in
# jail.{conf,local} configuration files.
destemail = root@localhost

# Default action to take: ban only
action = iptables[name=%(__name__)s, port=%(port)s]


[ssh]
enabled = true
port    = 22001
filter  = sshd
logpath  = /var/log/auth.log
banaction = iptables-allports
maxretry = 6


[apache]
enabled = true
port    = http
filter  = apache-auth
logpath = /var/log/apache*/*error.log
banaction = iptables-allports
maxretry = 6

Here I have set maxretry to 6 (although the default is still 3 at the top of th efile) meaning that 6 failed login attempts will trigger a ban. I have set bantime to 1800 meaning the use will be blocked for 30 minutes before they can try to log in again.

Notice that our SSH port is set to 22001 instead of "ssh" (which equates to 22).

Now restart fail2ban like so:

sudo /etc/init.d/fail2ban restart

If you want to test whether fail2ban is functioning, you can use a firewall tester.

If you want to get an idea of how many people are banned at a given moment, you can run:

sudo fail2ban-client status ssh

[edit] SSL and HTTPS

An SSL certificate allows you to have domains that begin with https:// instead of http:// . SSL can be a confusing realm to venture in to. But if you want to send data securely. If you are doing e-commerce, then SSL is essential. This easy to understand primer on SSL should help you understand the process of obtaining, a certificate and installing it on Apache.

For my server, I am using a Comodo certificate because it provided a good set of features at a reasonable price. Many different SSL providers exist and each will offer you varying levels of support, features, protection and encryption.

The instructions below should apply to most SSL providers, but I suggest you look into the documentation on their site.

Once you have signed up with an Certification Authority (CA) and they have verified you, you can follow the steps below to set up SSL on your server.

[edit] Generating a Certificate Signing Request (CSR) and Private Key

Run this command to install openssl, which will allow you to generate your side of the SSL transcation.:

sudo apt-get install openssl

Now you can generate your private key. You call it whatever you like (mykey-private.key is used here). Make sure you backup this file and keep it secure.

cd /etc/ssl
sudo openssl genrsa -des3 -out www.example.org.key 2048

You will be prompted to enter a passphrase. This will keep your key secure, but it will also mean that you have to enter the passphprase every time you restart Apache. If you really want to avoid this step, you can remove the -des3 flag from the command above, but that will leave you open to attacks if someone ever gets access to this file.

Use this key to generate a Certificate Signing Request (CSR):

sudo openssl req -new -key www.example.org.key -out www.example.org.csr

You will be prompted for the following information on your CSR. This should match the information you specified when signing up with your SSL provider. It is very important that the Common Name match the domain you want to provide SSL for. Most SSL certificate services only certify you for one domain, but if you purchase a wildcard service that let's you add SSL to any subdomain, make sure you enter *.example.org for your Common Name. The instructions below will enable HTTPS for www.example.org (which is the production site in our example), but won't allow you to use it HTTPS on staging.example.org. Keep that in mind when configuring your site.

Country Name (2 letter code) [AU]: US
State or Province Name (full name) [Some-State]: California
Locality Name (eg, city) []:  San Francisco
Organization Name (eg, company) [Internet Widgits Pty Ltd]: Fake Co, LLC
Organizational Unit Name (eg, section) []: Marketing Department
Common Name (eg, YOUR name) []: www.example.org
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []: Face Co, LLC
Note: You can lave the challenge password field blank in most cases. Check with your SSL provider to be sure.

Open www.example.org.csr in nano, copy the contents of the file and paste the results into the Comodo control panel at Control Panel > SSL Certificate > Provide CSR.

Comodo (or your SSL provider) will email you with a file ending in the extension .crt. This is your certificate.

Open the .crt file in a plain text editor on your local computer. Copy paste the contents of the .crt certificate file into a new file at /etc/ssl/certs/www.example.org.crt. Alternatively, you could use an SFTP client (like the ones mentioned in the introduction of this tutorial) to upload the file directly to the /etc/ssl/certs directory.

The text you are copying should look something like this. Do not include any extra whitespace or line breaks at the beginning or end of the file.

-----BEGIN CERTIFICATE-----

[encoded data]

-----END CERTIFICATE-----

Let's make sure we secure our key:

cd /etc/ssl
sudo chmod 400 www.example.org.key
sudo mv www.example.org.key private/www.example.org.key

[edit] Configuring Apache for SSL

Let's start by enabling the Apache SSL module

sudo a2enmod ssl

Open the ports.conf and confirm that it has the following lines. If not, then add them to the file:

File: /etc/apache2/ports.conf

<IfModule mod_ssl.c>
    Listen 443
</IfModule>

The next step is to ensure that the virtual host for our site is setup to handle SSL and to look for our key. Modify the configuration file for each site that you want to enable SSL for. Based on our virtual host definition at the beginning of this tutorial, here is what the modified host should look like (just add the stanza *:443 stanza to the end as nothing in the original definition has changed):

File: /etc/apache2/sites-available/staging.example.org

<VirtualHost staging.example.org:80>
     ServerAdmin [email protected]
     ServerName staging.example.org
     DocumentRoot /var/www/staging.example.org/public_html/
     ErrorLog /var/www/staging.example.org/logs/error.log
     CustomLog /var/www/staging.example.org/logs/access.log combined
     <Directory /var/www/staging.example.org/public_html/>
          Options Indexes FollowSymLinks MultiViews
          AllowOverride All
          Order allow,deny
          allow from all
     </Directory>
</VirtualHost>

<VirtualHost staging.example.org:443>
     SSLEngine on
     SSLCertificateFile /etc/ssl/certs/www.example.org.crt
     SSLCertificateKeyFile /etc/ssl/private/www.example.org.key 

     ServerAdmin [email protected]
     ServerName staging.example.org
     DocumentRoot /var/www/staging.example.org/public_html/
     ErrorLog /var/www/staging.example.org/logs/error.log
     CustomLog /var/www/staging.example.org/logs/access.log combined
     <Directory /var/www/staging.example.org/public_html/>
          Options Indexes FollowSymLinks MultiViews
          AllowOverride All
          Order allow,deny
          allow from all
     </Directory>
</VirtualHost>

Now restart Apache so the changes to your site will take effect:

a2r

[edit] Cron

Set up security tasks...

  • Trim logs?
  • Update Ubuntu?

[edit] Site on primary domain (www.example.org)

Now that the staging domain is up and running, you probably want to move everything over to the primary domain to deploy the site.

Here is what this stanza would look like if you weren't setting up a subdomain site. You don't need to add these unless you really are creating more than one site. This is just an example:

File: /etc/apache2/sites-available/example.org

<VirtualHost *:80>
     ServerAdmin [email protected]
     ServerName example.org
     ServerAlias www.example.org
     DocumentRoot /var/www/example.org/public_html/
     ErrorLog /var/www/example.org/logs/error.log
     CustomLog /var/www/example.org/logs/access.log combined
     <Directory /var/www/example.org/public_html/>
          Options Indexes FollowSymLinks MultiViews
          AllowOverride All
          Order allow,deny
          allow from all
     </Directory>
</VirtualHost>

Not the differences from before. In the <VirtualHost> definition, we use *:80 so that the server will accept traffic from www.example.org and example.org. We also added the ServerAlias www.example.org directive to tell the server to accept traffic from both.

And here are the folders for a non-subdomain site:

sudo mkdir -p /var/www/example.org/public_html
sudo mkdir -p /var/www/example.org/logs

Now enable the site:

sudo a2ensite example.org

[edit] Maintenance Tasks

Here is a list of things you should do on a daily/weekly basis to keep an eye on your server.

  • Check your free memory to make sure your app hasn't exploded recently
free -m
  • Check your fail2ban counts on the number of people currently banned:
sudo fail2ban-client status ssh
sudo fail2ban-client status apache
  • Check all your log files in /var/log/ using the less command.

[edit] Helpful Commands

  • Create a symbolic link to each of your sites to make them easier to access:
sudo ln -s /var/www/staging.example.org/public_html /staging
sudo ln -s /var/www/www.example.org/public_html /production
cd /production
  • Restart your server from the command line:
sudo shutdown -r now
  • To sync a MySQL dump to a database
mysql -u drupal_user -pPASWORDHERE database_name < DumpFromExistingMySQLdb.sql

[edit] Notes to self

  • Submit this to howtoforge.com


[edit] Revisions

  • 2009-08-07 Initial write-up begins
  • 2009-08-15 Finished initial revision (except for Drupal Deployment)

[edit] References and Further Reading

This tutorial is heavily based on other existing tutorials and various reference sites. To read more about any of the topics above, check out some of these sites:

General Apache, PHP, MySQL, Server Stuff:

Specific Topics:

SSL

Mail & Google Apps