A2 Hosting Ubuntu Virtual Private Server Guide
May 8, 2008
Table of Contents
1. Introduction
This guide documents my experience of purchasing a VPS hosting package at A2 Hosting, setting up a fresh Ubuntu server installation, and configuring several typical applications such as Apache, MySQL, PHP via FastCGI, and Ruby on Rails via Mongrel.
I have been a very happy customer of A2 Hosting for over a year and I recommend them very highly. They provide an array of very affordable, high quality hosting packages and their support team has continued to impress me with their responsiveness and receptiveness to feedback.
I hope to create value for myself and others by writing this guide as I work through the process myself. If you find this guide useful and decide to create an account yourself, please do so by visiting them via this link. I will receive a percentage-based commission for every new account created this way.
2. Virtual Private Servers
A virtual private server (VPS) is a “slice” of a real physical server which runs its own operating system and is completely isolated from the rest of the system. Each VPS is given a share of the memory, storage, and CPU time of the physical server as well as its own IP address. Many hosting providers are beginning to offer VPS packages at rates that are approaching that of shared hosting.
VPS hosting has many advantages over shared hosting:
Full root access, allowing you to choose which packages are installed and how they are configured. You will never have to submit a ticket to get a Perl module or Ruby gem installed.
You will have a clearly defined minimum guaranteed amount of memory and percentage of the CPU.
Services such as Mongrel are not very well suited to shared hosting environments. It can be done (A2 hosting provides excellent shared hosting packages which support Ruby on Rails via Mongrel) but such shared hosting packages typically limit the number of Mongrel instances you can run.
Full control over your DNS records. You can even host your own nameserver if you like.
3. Ordering
The ordering process is very simple. First, review the available VPS hosting packages. They differ primarily in terms of hard disk space, memory, and CPU share. A2 allows you to upgrade or downgrade at any time so you can start experimenting with a small base package upgrade later if necessary.
If you need a domain name, they will register one for you at the same time and assign it to your new virtual server. If you have an existing domain at another registrar that you would like to use, you can request to have that domain transferred to A2 or you can opt to leave the domain at the existing registrar and set up the DNS yourself by pointing your domain to A2’s nameservers.
If you place your order during normal (US/Eastern) business hours, you should get a welcome email within a few hours saying your account is ready and providing URLs, usernames and passwords for your HyperVM control panel, DNS management, and SSH login. Your virtual server will have its own unique IP address. Note that SSH is on a nonstandard port for security reasons.
4. Server Configuration
Securing Your New Server
Your initial password is emailed to you in plain text. This same password is used for the A2 Hosting billing system, the HyperVM control panel, the DNS control panel, and for loging in to the server via SSH. You should change these immediately for security reasons.
Installing Ubuntu
By default the CentOS 5 image is used. This guide was written for the
Ubuntu 7.10 barebones server image. To use the Ubuntu image, visit the
HyperVM control panel using the link you received in the welcome email.
Choose Console | Rebuild and select the ubuntu-7.10-i386-a2hosting
image. This image has the added benefit that it’s very small—only
135.5 MB—leaving plenty of space for data and applications.
First steps
This guide involves editing a lot of configuration files. I will
sometimes write commands that assume that you will be using vi
. If
you’re not comfortable with vi
, you may want to install something else
such as nano
.
You can now login (as root) to your new Ubuntu VPS using the root password that was emailed to you:
% ssh -p 7822 <IP ADDRESS> -l root
Immediately change your password:
# passwd
Next, there is a small issue with the locale settings that you can go ahead and fix now. Otherwise, you might receive warning messages like “perl: warning: Setting locale failed” when trying to install various programs. To fix this, run:
apt-get install --reinstall language-pack-en
or replace the en
with your desired language. Generating the locales will
take a couple of minutes.
Next, update your /etc/apt/sources.list
to enable a wider selection of
packages from universe, multiverse, restricted, security updates, and
backports:
deb http://us.archive.ubuntu.com/ubuntu/ gutsy main universe multiverse restricted
deb http://us.archive.ubuntu.com/ubuntu/ gutsy-updates main restricted
deb http://us.archive.ubuntu.com/ubuntu/ gutsy-backports main restricted universe multiverse
deb http://security.ubuntu.com/ubuntu gutsy-security main restricted universe multiverse
Update the package database:
# apt-get update
Upgrade to the latest version of all base packages:
# apt-get upgrade
After that, you might want to install a few extra packages (apt-get install
<package>
) to make life a little easier:
bash
- a shell with a few more bells and whistles thansh
.man
- You will probably need to read a few manpages along the way.cron
- for scheduling tasks.wget
- very useful for downloading files.rsync
- an excellent file transfer tool.vim
- A lightweight console editor with syntax highlighting.lynx
- A lightweight console browser.git
- distributed version control.
Adding a New User
You should do most of your work as a normal user instead of as root so that
later on you can’t take down your system and precious data with a simple
typo. First, install the adduser
package and then add the new user:
# apt-get install adduser
# adduser <username>
Before you log out of the root account, you want to make sure the normal user
account can run commands as root
using sudo
. Edit /etc/sudoers
and
add the following to the end:
<username> ALL=(ALL) ALL
Now, log out (type exit
or press CTRL+D) and log in again as the normal
user:
% ssh -p7822 <IP ADDRESS> -l <username>
Securing Your SSH Server
By default, VPS systems at A2 Hosting use port 7822 instead of 22, the
default. This will provide some protection from brute force attacks, but
it’s still possible for someone to scan your ports and find the SSH server.
There are a few more precautions you can take by making the following
changes in /etc/ssh/sshd_config
:
Disable root logins by changing
PermitRootLogin
fromyes
tono
.If you are the only person who will be logging in, you can limit logins to only your username by adding
AllowUsers <username>
.
Once you are done, restart the SSH server:
% sudo /etc/init.d/ssh restart
5. DNS
Existing Domain
To point an existing domain at another registrar to your VPS you will need to use the DNS control panel provided by the current registrar as well as the DNS management URL and nameserver IP addresses provided in the A2 Hosting welcome email.
First, change the nameservers to the two IP addresses that A2 Hosting provided in the welcome email:
- ns1.a2webhosting.com: 69.39.89.180
- ns2.a2webhosting.com: 67.18.111.123
Then, login to A2’s DNS management site and add a new DNS zone for the domain:
- Go to DNS Functions | Add a DNS Zone.
- Enter the IP address of your VPS and your domain name.
- Select your account.
- Click Add Zone.
It may take a few hours for the new entry to propagate. Your domain should
now point to the VPS. You can check this by running nslookup foo.com
.
The changes could take up to a day to propagate so don’t panic if it doesn’t
happen fast.
You can point many different domains to the same VPS and configure Apache to serve them as virtual hosts (below).
6. Apache
Install Apache:
% sudo apt-get install apache2
The configuration files are located in /etc/apache2
and the default
document root is in /var/www
.
When the installation finishes, the system will try to start Apache but
depending on your VPS package, there may not be enough memory available.
You can check to see if it started by visiting your VPS’s IP address in
your browser or typing ps aux
and looking for apache2
. If not, you
will need to follow the steps below to reduce its memory consumption.
Performance tuning
By default, Apache is configured to spawn many different threads when it starts. Depending on which package you chose, it may not even start due to insufficient memory. If your site does not handle enough traffic to warrant a dedicated server, you can most likely stand to decrease the Apache defaults a bit.
In /etc/apache2/apache2.conf
, consider each of the following changes:
Decreasing
Timeout
to, say, 60 seconds in order to maintain a low number of processes (Ubuntu default: 300).Setting
MaxKeepAliveRequests
to 0 to allow unlimited KeepAlive requests so that multiple requests from the same client can be served without initiating new connections (Ubuntu default: 100).Decreasing
KeepAliveTimeout
to 2 or 3. Then, if no new requests are received within 2 or 3 seconds, the connection is killed. Hopefully requests will be served fast enough so that this will provide enough time for any subsequent requests without keeping connections open too long (Ubuntu default: 15).
Multi-Processing Modules
Apache is designed to use Multi-Processing Modules, or MPMs, which bind to a
port on the server, accept incoming requests, and send the requests to child
processes to be handled. On Ubuntu, Apache is compiled to use “worker” MPMs
(as opposed to “prefork”). You can check this by running apache2 -l
:
% apache2 -l
Compiled in modules:
core.c
mod_log_config.c
mod_logio.c
worker.c
http_core.c
mod_so.c
From the Apache documentation on the worker MPM:
This Multi-Processing Module (MPM) implements a hybrid multi-process multi-threaded server. By using threads to serve requests, it is able to serve a large number of requests with less system resources than a process-based server. Yet it retains much of the stability of a process-based server by keeping multiple processes available, each with many threads.
On Linux, each child process will use 8MB of memory by default. This is
probably unnecessary. You can decrease the overall memory used by Apache by
setting ThreadStackSize
to 1MB in /etc/apache2/httpd.conf
:
ThreadStackSize 1000000
I’m presently experimenting with 1MB but I may move it up to 2MB (or down to
512K) if needed, depending on the requirements of any modules I need to load.
There is an informative thread regarding memory usage on the apache-dev
list.
You will almost certainly need to decrease the default number of child
processes loaded. The number of processes started automatically is governed
by the StartServers
directive. Each process has ThreadsPerChild
server
threads plus one listener thread which passes incoming connections off to
server threads. Apache also maintains a pool of of spare threads that stand
by and wait to handle any new requests. New processes are started or
existing ones are killed so that there are always at least MinSpareThreads
and at most MaxSpareThreads
of these spare threads.
MaxRequestsPerChild
sets the maximum number of requests served by a child
process before it is recycled. There may be a number of processes which are
ready to terminate but which have threads that are still serving clients. Up
to MaxClients
of these processes are allowed.
Here are the default settings:
<IfModule mpm_worker_module>
StartServers 2
MaxClients 150
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
MaxRequestsPerChild 0
</IfModule>
I reduced them as follows:
<IfModule mpm_worker_module>
StartServers 2
MaxClients 50
MinSpareThreads 10
MaxSpareThreads 25
ThreadsPerChild 10
MaxRequestsPerChild 500
</IfModule>
Virtual Hosts
To enable name-based virtual hosting, place the line
NameVirtualHost 66.103.254.221:80
(replace this with your own IP) somewhere in your apache2.conf
before the
line
Include /etc/apache2/sites-enabled/
In /etc/apache2/sites-available
create a file for each virtual host, say
/etc/apache2/sites-available/jblevins.org
. In this file, put something
like the following:
<VirtualHost 66.103.254.221:80>
ServerName jblevins.org
ServerAlias www.jblevins.org
ServerAdmin jrblevin@sdf.lonestar.org
DocumentRoot /var/www/jblevins.org
<Directory /var/www/jblevins.org>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>
ErrorLog /var/log/apache2/jblevins.org-error.log
LogLevel warn
CustomLog /var/log/apache2/jblevins.org-access.log combined
ServerSignature On
</VirtualHost>
In this example, 66.103.254.221 is the IP address of the VPS (replace this
with your own), 80 is the port that Apache is listening on, the document root
for jblevins.org
is /var/www/jblevins.org
and there will be separate
access and error logs for this domain in /var/log
.
Create a symbolic link in sites-enabled
to the configuration file in
sites-available
:
% cd /etc/apache2/sites-enabled
% sudo ln -s ../sites-available/jblevins.org 001-jblevins.org
Restart apache:
% sudo /etc/init.d/apache2 restart
A Note About Permissions
Note that by default on Ubuntu, Apache runs with user www-data
and group
www-data
. Apache needs to be able to read your files so wherever you place
your document root, the files will need to be either world-readable or owned
by www-data
. Furthermore, if you will be running CGI scripts that need to
write to files, they will need to be writable by the user or group
www-data
. Any new file that is created will be owned by www-data
and thus you will not be able to modify it under your usual username.
A simple but inelegant solution is to simply add yourself to the
www-data
group:
% sudo adduser <username> www-data
If your VPS is effectively a single-user system, this should be good enough.
There is a more elegant way around this, but the details and security
implications are beyond the scope of this document. If your virtual host’s
DocumentRoot falls under /var/www
then you should be able to load
mod_suexec
and add the line SuexecUserGroup <username> <group>
to the
VirtualHost block. Apache will then execute any CGI scripts as if they were
executed by the given user and group. For more details, take a look at the
suexec documentation.
Log Rotation
You can pipe your access and error logs to a program like cronolog which will automatically rotate them for you at specific time intervals (or file sizes). You can install it from the Ubuntu repositories:
% sudo apt-get install cronolog
You can set up monthly log rotation by adding the following to httpd.conf
:
CustomLog "|/usr/sbin/cronolog /var/log/apache2/access-%Y%m.log" combined
You can do this at the VirtualHost level and for error logs as well. If you
want cronolog to maintain a symbolic link to the current log, use the
--symlink
option. See the documentation for other options.
Log Splitting
Install vlogger:
% apt-get install vlogger
Change the log format, in /etc/apache2/apache2.conf
, to include the virtual host:
[...]
#LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
[...]
Pipe your logs through vlogger:
[...]
CustomLog "| /usr/sbin/vlogger -s access.log /var/log/apache2" combined
[...]
Server Status
Since the server is relatively resource constrained, you might want to keep
an eye on it during periods of heavy usage so you can tweak your configuration.
You can enable a status page to monitor your server using mod_status. To do
this, make sure you have links to status.conf
and status.load
in
/etc/apache2/mods-enabled
and add the following to your httpd.conf
file:
# Server Status (mod_status)
ExtendedStatus On
<Location /server-status>
SetHandler server-status
Order deny,allow
Deny from all
Allow from .yourdomain.com
</Location>
The ExtendedStatus
directive gives you the highest possible level of detail
and the Order
, Deny
, and Allow
directives ensure that only visitors
from .yourdomain.com
can view the site. Alternatively, you can restrict
access to specific IP addresses, etc.
7. CPAN
You can then install CPAN Perl modules system-wide by running the following command as root (using the Net::Akismet module as an example):
# cpan install Net::Akismet
8. MySQL
Install the MySQL packages:
% sudo apt-get install mysql-server mysql-client
You will be asked for a root password. Note that by default, MySQL is
configured to listen only on localhost
. This should be fine for running
web applications locally. If you want to allow outside access to the MySQL
server, you need to edit /etc/mysql/my.cnf
and uncomment the line
bind-address = 127.0.0.1
.
MySQL will use a ton of memory (on the order of 128 MB) under the default configuration. For now, stop the server:
% sudo /etc/init.d/mysql stop
The MySQL configuration file is /etc/mysql/my.cnf
. You probably want to at
least disable InnoDB by uncommenting the skip innodb
line, saving around
100 MB of memory. Here are few other guides to running MySQL with a
small memory footprint:
VPS MySQL and Apache Optimization Guide- Optimizing Apache and MySQL for Low Memory Usage, Part 2
- Example mysql config file for small systems
9. PHP
The following instructions, based on a guide posted to the Ubuntu Forums, show how to use PHP5 in a virtual hosting environment using suexec to maintain separate privileges for each host. FastCGI is used instead of mod_php so that we can continue to use the threaded worker MPM. mod_php is not thread safe and installing it would require using the older prefork MPM which tends to use more memory than the worker MPM. You will need to install the following packages:
% sudo apt-get install libapache2-mod-fastcgi php5-cgi
Then configure and the fastcgi module by adding
FastCgiConfig -pass-header HTTP_AUTHORIZATION
to /etc/apache2/mods-available/fastcgi.conf
so that HTTP authorization will
work and run
% sudo a2enmod fastcgi
to enable the module.
We need to write a wrapper script for PHP that lies under /var/www
since
suexec does not permit running scripts outside the DocumentRoot.
Create a directory /var/www/php-fastcgi
and a wrapper script
/var/www/php-fastcgi/php5-fcgi
containing the following:
#!/bin/bash
export PHPRC="/etc/php5/cgi"
export PHP_FCGI_MAX_REQUESTS=499
exec /usr/bin/php5-cgi
This script will be used for PHP5. You can do the same for PHP 4 if you like. Now, set the appropriate permissions for the directory and script:
% sudo chown -R www-data.www-data /var/www/php-fastcgi
% sudo chmod +x /var/www/php-fastcgi/php5-fcgi
We need to make this script available as a handler for .php
files through
the Apache configuration files. You can do this at the server, virtual host,
or directory level:
## PHP-FastCGI
<IfModule mod_fastcgi.c>
<Directory /var/www/php-fastcgi>
SetHandler fastcgi-script
Options ExecCGI FollowSymLinks
</Directory>
Alias /php-fastcgi /var/www/php-fastcgi
AddHandler php5-fcgi .php
Action php5-fcgi /php-fastcgi/php5-fcgi
</IfModule>
Now, assuming you have used SuexecUserGroup <username> <group>
in your
virtual host configuration, any .php
files should be handled by FastCGI and
executed as the specified user and group.
10. Email
To be able to send and receive email you will need to install and
configure exim4
:
% sudo apt-get install exim4
% sudo dpkg-reconfigure exim4
During the configuration, choose “Internet Site” and listen on IP
address: <IP ADDRESS>:127.0.0.1
where <IP ADDRESS>
is the IP address
of your VPS.
11. Rails and Mongrel
Installing Rails and Mongrel is simple:
% sudo apt-get install ruby rubygems irb rails mongrel
You probably want to create symbolic links under /usr/local/bin
as
many scripts will look for Ruby there.
% sudo ln -s /usr/bin/ruby1.8 /usr/local/bin/ruby
% sudo ln -s /usr/bin/ri1.8 /usr/local/bin/ri
% sudo ln -s /usr/bin/rdoc1.8 /usr/local/bin/rdoc
% sudo ln -s /usr/bin/irb1.8 /usr/local/bin/irb
You can now run your Rails applications with Mongrel using the
mongrel_rails start
command. Mongrel will run on a port other than 80
but it is fairly straightforward to configure Apache to proxy for
Mongrel using mod_proxy
.
12. Miscellaneous Notes
Adding yourself to the
www-data
group and giving the server write permissions to a certain directory:% sudo adduser jrblevin www-data
Log out and log back in so that the new group is effective and then change the ownership and permissions of the target directory, say,
public_html
:% chgrp -R www-data public_html % chown -R g+w public_html
You can set your hostname through the A2 Hosting VPS control panel, under Network. After you change it, you can verify it by running
hostname -f
.Set the server to your local timezone (US/Eastern for example):
% sudo rm -rf /etc/localtime % find /usr/share/zoneinfo/ | more % sudo ln -s /usr/share/zoneinfo/US/Eastern /etc/localtime
Keep your system clock synchronized with
ntpd
:% sudo apt-get install ntp
Reboot the server:
% sudo shutdown -r now
To add a subdomain, for example,
code.jblevins.org
:Visit the VPS DNS Control Panel and select DNS Functions | Edit DNS Zone.
Select the domain
jblevins.org
and click Edit.Add a CNAME entry for the subdomain:
code | 14000 | CNAME | jblevins.org