Skip to content

Setting up and securing web server (+MySQL +Rails/PHP) on Ubuntu 10.04 LTS

After repeating these operations many times in various setups, I decided to create a public set of instructions and share them with the world. This should be suitable for most of the simple web sites, utilizing Ruby on Rails or PHP.

The setup works on Ubuntu 10.04 Server LTS (scheduled end of life April 2015). Other components of the setup are Nginx as the web server, Phusion Passenger as application server.

I’m using this setup most often on Linode VPS, however none of the instructions are Linode specific.

Create non-root user with sudo rights

(Login as root via ssh)

Add a new user (this user will be an administrator of the server – will have the ability to log in via ssh and use sudo, it is different from user account used for the web application):

adduser username

Add this user to sudoers list:


in the editor add

username ALL=(ALL) ALL

Securing sshd

Edit /etc/ssh/sshd_config:

Change the following lines (note, you’re changing default port for ssh connections – you’ll need to take that into account when connecting to the server later):

Port 6668
PermitRootLogin no
X11Forwarding no
Protocol 2
PasswordAuthentication no
UsePAM no

Add the following lines (here username is the name of the administrator user that was created earlier):

UseDNS no 
AllowUsers username

Restart ssh daemon:

/etc/init.d/ssh restart

Add authentication keys for new administrator user

Note, that ‘user’ here is the name of the administrator user that was created earlier.

mkdir /home/user/.ssh 
vim /home/user/.ssh/authorized_keys

When editing authorized_keys file, insert a public of that user (e.g. your personal public key, if you want to make yourself an administrator).

chown -R user:user /home/user/.ssh 
chmod 600 /home/user/.ssh/authorized_keys

Now you can log out as root and log in as a sudo user you just created. NOTE! You won’t be able to log in as rot via ssh anymore.

Set up iptables firewall

Save existing rules

sudo sh -c 'iptables-save > /etc/iptables.up.rules'

Create test rules

sudo vim /etc/iptables.test.rules

Here’s an example of the firewall setup:


#  Allows all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d -j REJECT

#  Accepts all established inbound connections

#  Allows all outbound traffic
#  You can modify this to only allow certain traffic

# Allows HTTP and HTTPS connections from anywhere (the normal ports for websites)
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT

# (alternative) Uncomment to allow HTTP connections only from frontend server
# -A INPUT -p tcp -m state --state NEW -s frontend.server.ip --dport 80 -j ACCEPT

# Allow SSH connections
-A INPUT -p tcp -m state --state NEW --dport 6668 -j ACCEPT

# Uncomment to allow MySQL connections from defined servers
#-A INPUT -p tcp -m state --state NEW -s app.server.1.ip --dport 3306 -j ACCEPT

# Uncomment to allow memcached connections from app servers
#-A INPUT -p tcp -m state --state NEW -s app.server.1.ip --dport 11211 -j ACCEPT

# Uncomment to allow ping
#-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT

# log iptables denied calls
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7

# Reject all other inbound - default deny unless explicitly allowed policy


Apply firewall rules:

sudo iptables-restore < /etc/iptables.test.rules

Check if everything is correct

sudo iptables -L

If everything is fine, save the rules

sudo sh -c 'iptables-save > /etc/iptables.up.rules'

Make sure firewall rules are applied as soon as network interface comes up:

sudo vim /etc/network/interfaces

Add in the editor

pre-up iptables-restore < /etc/iptables.up.rules
iface lo inet loopback

Fix locales

sudo locale-gen en_GB.UTF-8 
sudo /usr/sbin/update-locale LANG=en_GB.UTF-8

Set timezone and hostname

sudo dpkg-reconfigure tzdata

Select your timezone

sudo sh -c 'echo "name" > /etc/hostname' 
sudo hostname -F /etc/hostname

Edit /etc/hosts (insert your VPS IP address and your server hostname here) hostname

Update the system

Uncomment universe repositories

sudo vim /etc/apt/sources.list

And run safe and full upgrades

sudo aptitude update 
sudo aptitude safe-upgrade 
sudo aptitude full-upgrade

Install build essentials

sudo aptitude install build-essential 
sudo apt-get install zlibc zlib1g-dev libcurl4-openssl-dev libreadline5-dev

Install setlock for crontab

sudo apt-get install daemontools

Set up Ruby Enterprise Edition 2012.02

Install ruby-ee (ruby 1.8.7 (2012-02-08 MBARI 8/0x6770 on patchlevel 358) [x86_64-linux], MBARI 0x6770, Ruby Enterprise Edition 2012.02):

mkdir ~/tmp 
cd ~/tmp 
tar xvzf ruby-enterprise-1.8.7-2012.02.tar.gz

Now enable tc_malloc large pages feature (32bit systems only):

sudo ./ruby-enterprise-1.8.7-2012.02/installer

Create soft links to ruby tools

sudo ln -s /opt/ruby-enterprise-1.8.7-2012.02/bin/ruby /usr/local/bin/ruby
sudo ln -s /opt/ruby-enterprise-1.8.7-2012.02/bin/gem /usr/local/bin/gem
sudo ln -s /opt/ruby-enterprise-1.8.7-2012.02/bin/irb /usr/local/bin/irb
sudo ln -s /opt/ruby-enterprise-1.8.7-2012.02/bin/rake /usr/local/bin/rake
sudo ln -s /opt/ruby-enterprise-1.8.7-2012.02/bin/bundle /usr/local/bin/bundle

Create parametrised ruby launcher

sudo vim /usr/local/bin/ruby-with-env

With the following content:

export RUBY_HEAP_MIN_SLOTS=1500000 
export RUBY_GC_MALLOC_LIMIT=50000000 
exec "/usr/local/bin/ruby" "$@"

and make this file executable:

sudo chmod +x /usr/local/bin/ruby-with-env

Set up necessary components

Install readline wrap

sudo apt-get install rlwrap

Install git

sudo apt-get install git-core

Install native dependencies for gems

sudo apt-get install libcurl4-gnutls-dev libxslt-dev libssl-dev

Install MySQL

sudo apt-get install mysql-server libmysqlclient-dev

Install Passenger 3.0.11 and let it compile nginx

cd /tmp wget
tar xvzf nginx-1.0.14.tar.gz 
sudo /opt/ruby-enterprise-1.8.7-2012.02/bin/passenger-install-nginx-module

– choose installation option 2
– provide source path /tmp/nginx-1.0.14
– provide additional compilation options –with-http_realip_module –with-http_gzip_static_module –without-mail_pop3_module –without-mail_smtp_module –without-mail_imap_module

Create nginx init script:

sudo vim /etc/init.d/nginx

Enter the following content:

#! /bin/sh

# Provides:          nginx
# Required-Start:    $all
# Required-Stop:     $all
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts the nginx web server
# Description:       starts nginx using start-stop-daemon


test -x $DAEMON || exit 0

# Include nginx defaults if available
if [ -f /etc/default/nginx ] ; then
    . /etc/default/nginx

set -e

. /lib/lsb/init-functions

test_nginx_config() {
  if nginx -t
    return 0
    return $?

case "$1" in
    echo -n "Starting $DESC: "
    start-stop-daemon --start --quiet --pidfile /var/run/$ \
        --exec $DAEMON -- $DAEMON_OPTS || true
    echo "$NAME."
    echo -n "Stopping $DESC: "
    start-stop-daemon --stop --quiet --pidfile /var/run/$ \
        --exec $DAEMON || true
    echo "$NAME."
    echo -n "Restarting $DESC: "
    start-stop-daemon --stop --quiet --pidfile \
        /var/run/$ --exec $DAEMON || true
    sleep 1
    start-stop-daemon --start --quiet --pidfile \
        /var/run/$ --exec $DAEMON -- $DAEMON_OPTS || true
    echo "$NAME."
        echo -n "Reloading $DESC configuration: "
        start-stop-daemon --stop --signal HUP --quiet --pidfile /var/run/$ \
            --exec $DAEMON || true
        echo "$NAME."
        echo -n "Testing $DESC configuration: "
        if test_nginx_config
          echo "$NAME."
          exit $?
    status_of_proc -p /var/run/$ "$DAEMON" nginx && exit 0 || exit $?
    echo "Usage: $NAME {start|stop|restart|reload|force-reload|status|configtest}" >&2
    exit 1

exit 0

Make it executable:

sudo chmod +x /etc/init.d/nginx

Add nginx to autostartup list:

sudo /usr/sbin/update-rc.d -f nginx defaults

Edit main nginx config

sudo vim /opt/nginx/conf/nginx.conf

Enter the following content:

user  www-data;
worker_processes  4;

error_log  /var/log/nginx/error.log;
pid        /var/run/;

events {
    worker_connections  8192;
    use epoll;

http {
    passenger_root /opt/ruby-enterprise-1.8.7-2012.02/lib/ruby/gems/1.8/gems/passenger-3.0.11;
    passenger_ruby /usr/local/bin/ruby-with-env;

    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log;

    sendfile       on;
    tcp_nopush     on;
    tcp_nodelay        on;
    keepalive_timeout  65;

    # Passenger never sleeps!
    passenger_pool_idle_time 0;

    # Use more instances, because memory is enough
    passenger_max_pool_size 15;

    # Start application instantly

    client_max_body_size 4m;

    include /opt/nginx/conf/sites-enabled/*;

Create site configuration and log directories:

sudo mkdir /opt/nginx/conf/sites-enabled 
sudo mkdir /opt/nginx/conf/sites-available 
sudo mkdir /var/log/nginx

Set up virtual hosts

Create a separate user for each virtual host, create a home directory, set password, create folder for logs and web application, set permissions

sudo useradd newuser -d /home/newuser 
sudo mkdir /home/newuser 
sudo passwd newuser password
sudo mkdir /home/username/hostname 
sudo mkdir /home/username/logs 
sudo mkdir /home/username/logs/hostname 
sudo chown -R username:www-data /home/username/ 
sudo chmod 750 /home/username/

Configure hosts:

sudo vim /opt/nginx/conf/sites-available/
server {
        listen   80;

        access_log  /home/user/logs/;
        error_log  /home/user/logs/;
        root   /home/user/;
        # uncomment if traffic is coming from a frontend server/loadbalancer
        #real_ip_header     X-Real-IP;

        passenger_enabled on;
        passenger_min_instances 5;

Enable site:

sudo ln -s /opt/nginx/conf/sites-available/ /opt/nginx/conf/sites-enabled/

Set up log rotation:

sudo ln -s /home/user/ /etc/logrotate.d/mysite

Install fastcgi (for PHP setups)

Install dependencies

sudo apt-get install libmcrypt-dev libxml2-dev libpng-dev autoconf2.13 libevent-dev libltdl-dev

Download latest stable PHP 5.2.13, Suhosin patch, PHP-FPM patch

cd ~/tmp wget
tar xvzf php-5.2.13.tar.gz gunzip suhosin-patch-5.2.13-0.9.7.patch.gz 
gunzip php-5.2.13-fpm-0.5.13.diff.gz 
cd php-5.2.13 
patch -p 1 -i ../php-5.2.13-fpm-0.5.13.diff 
patch -p 1 -i ../suhosin-patch-5.2.13-0.9.7.patch 
./buildconf --force 
./configure --enable-fastcgi --enable-fpm --with-mcrypt --with-zlib --enable-mbstring --with-openssl --with-mysql --with-mysql-sock --with-gd --without-sqlite --disable-pdo 
make test 
sudo make install

Alternatively download latest stable PHP 5.3.2, Suhosin patch, apply PHP-FPM patch

cd ~/tmp
tar xvzf php-5.3.2.tar.gz gunzip suhosin-patch-5.3.2- 
cd php-5.3.2 
patch -p 1 -i ../suhosin-patch-5.3.2- 
svn co sapi/fpm 
./buildconf --force 
./configure --enable-fastcgi --enable-fpm --with-mcrypt --with-zlib --enable-mbstring --with-openssl --with-mysql --with-mysql-sock --with-gd --without-sqlite --disable-pdo --disable-reflection 
make test 
sudo make install

Uninstall autoconf2.13 after compilation, since it is an old version and only required for PHP compilation

sudo apt-get uninstall autoconf2.13

Change user and group of php-fpm processes to your user dedicated to this application and www-data – lines 63 and 66 respectively

sudo vim /usr/local/etc/php-fpm.conf

Edit PHP settings

sudo vim /etc/php5/cgi/php.ini


max_execution_time = 30 
memory_limit = 64M 
display_errors = Off 
log_errors = On 
error_log = /var/log/php.log 
register_globals = Off
Now restart nginx and you’re all set
sudo  /etc/init.d/nginx restart


  1. ハウディ|プラットフォームあなたののためのサイトのブログのWordpressを使用していますか?私は、ブログの世界に新たなんだけど、始めるしようと作るよ私自身を。あなたが必要でくださいどんな htmlのコーディング|自分のブログを作るために知識ノウハウを?すべてのヘルプは大いにされるであろうが理解!

    Tuesday, September 22, 2015 at 16:33 | Permalink
  2. Anonymous wrote:

    私はブログ何かを見つけるために好奇心プラットフォーム あなたがされている利用と協力?いくつかのマイナーセキュリティを|私の写真と一緒に問題問題|私は持つ経験だと私がう見つけたいものより守ら安全な。 何かありますか?

    Wednesday, September 23, 2015 at 9:31 | Permalink
  3. Anonymous wrote:


    Wednesday, September 23, 2015 at 19:44 | Permalink
  4. I was upgraded on regular basis about development on my PC fault and
    replacement HD. All information/ program’s rebuilt and even recuperated
    our emails.

    Thursday, September 24, 2015 at 14:56 | Permalink
  5. Lon wrote:

    Lastly, lots of people utilize their binoculars at sunset, in overcast conditions, and at night,
    when their pupils are bigger.

    Thursday, September 24, 2015 at 17:16 | Permalink
  6. Sammy wrote:

    The all-purpose use binoculars that we examined right here fall in between the
    low magnification and the medium magnification varieties.

    Thursday, September 24, 2015 at 18:16 | Permalink
  7. Sallie wrote:

    Choosing the very best professional binocular substance microscope from the many available on the market is a little a difficulty.

    Thursday, September 24, 2015 at 18:25 | Permalink
  8. Dena wrote:

    Field glasses, which are compact binoculars like the ones shown in the picture right here, turn the incoming images making use of only lenses.

    Friday, September 25, 2015 at 6:23 | Permalink
  9. Courtney wrote:

    The specific size can be measured by dividing the unbiased lens by the magnification of the binoculars.

    Friday, September 25, 2015 at 7:17 | Permalink
  10. Shoshana wrote:

    Binoculars are explained with 2 numbers separated by an x.
    For instance, the field glasses in the picture above are
    8 x 21. The first number is the magnification.

    Friday, September 25, 2015 at 7:42 | Permalink
  11. Lemuel wrote:

    Divide the diameter of the front unbiased lens (in millimeters) by the zoom of the

    Saturday, September 26, 2015 at 9:10 | Permalink
  12. csgo account wrote:

    I don’t even understand how I ended up right here, however I thought this post was good.

    I don’t recognize who you are but certainly you’re going to a
    well-known blogger in case you are not already. Cheers!

    Saturday, October 17, 2015 at 17:20 | Permalink

Post a Comment

Your email is never published nor shared. Required fields are marked *