I enjoy coding websites. I like coming up with elegant and flexible solutions to problems. If you saw David Heinemeier Hanssons' early screen casts on web development with Ruby on Rails, you may have been as impressed as I was. Unfortunately, deployment of a website to a *nix server can be a daunting task if you haven't done it before. It doesn't matter if it is a PHP, Python, or Ruby on Rails website, you need to have some basic sysadmin skills to set everything up on a newly installed server. You've got to know something about web servers (Apache, NginX, etc.), something about databases (MySQL, Postgres), about firewalls (iptables or Shorewall), source control (Subversion), email (SendMail, Postfix), monitoring your server (Monit, Nagios), statistics (Awstats, etc.), log rotation, cron jobs, offsite backups (Amazon s3). I have yet to meet an expert in all of these areas. For those sysadmins out there that fit the description I bow deeply. I've decided to do a series on setting up a full Rails stack on Ubuntu. So far I have deployed production Rails web applications to Red Hat, Open Solaris, CentOS, and Ubuntu servers. I've learned enough to know how truly ignorant I am. I don't claim to be an expert. But I am willing to share what I've learned so far in hopes it will help others out there. Here is what you'll get (in no particular order) when finished with the series.
- SSH Keys
- Setting Up Aliases
- Nginx
- Ruby, RubyGems, Rails
- ImageMagick, RMagick
- Mongrel, Mongrel Cluster
- Monit
- AwStats
- Webmin
- Postfix
- MySQL
- Log Rotation
- Capistrano 2 Deployment
- Webistrano setup
- Amazon s3 backup
- Cron Job setup
- Subversion
- Shorewall Firewall
The usual disclaimer applies about not blaming me if things go awry on your machine. The following is working great for me right now on production servers. Your mileage may vary.
But, before we begin, please note that I am aware of the many automated ways that are available to setup a server such as RubyWorks by ThoughtWorks, the RailsMachine gem, Machinify, deprec, etc. When I first was learning about deployment I tried most of these out. Unfortunately, in my opinion, if you don't know how, where, and why things are installed on your server, it can lead to problems in the future. Trust me, it is much better to learn about how things work up front, that way you can deal with unique client requests that these automated solutions can't possibly account for. For example, I just recently deployed a Ruby on Rails forum that uses a Microsoft SQLServer 2000 database the client already had and wanted to use. If I hadn't learned some basic sysadmin skills, I would have been up a creek.
So let's get started. Here are my basic assumptions. You've got a brand new *nix server (the commands will assume Ubuntu Linux but the steps used can be applied to any *nix server) installed that is up and running. If you don't have a server I would recommend looking at SliceHost for small to medium sites. They are affordable and have been quite reliable for me (they run VPS slices on Xen servers). You should have the SSH credentials for the server. You also need a way to SSH into the server. For Mac it is built in (Terminal application), on a PC you can download Putty. Lets do a quick connection test and setup a new user on the server. Open up Terminal or Putty and connect to your server (you will be prompted for your password):
-
ssh root@your_linux_box.com
Now create a new user called deploy:
-
adduser deploy
Now lets grant our new user sudo access. Type "visudo" and scroll down to the bottom and add our deploy user under the root section:
-
sudo visudo
-
deploy ALL=(ALL) ALL
Save the file and exit out of the text editor. Type "exit" to get out of our ssh sesssion and return to our client machine. Change directories to your home directory on your Mac:
-
cd ~
Our first full step is one of convenience for Mac users and isn't absolutely necessary. We are going to setup SSH keys so that we won't be prompted for a password every time we want to SSH into our server. This will make our Capistrano deployments seamless later on. First we need to create a public key on our Mac. You can generate an SSH RSA key with your email as an added comment using the ssh-keygen command. The following command will create two files, id_rsa and id_rsa.pub, in your .ssh/ directory:
-
ssh-keygen -t rsa -f ~/.ssh/id_rsa -C "your@emailaddress.com"
Now lets create the .ssh directory on our server. We can actually create this folder without executing any commands on the Linux server. We use SSH to remotely execute the command from our client machine so you don't need to run the following command on your Linux server.
-
ssh deploy@your_linux_box.com 'mkdir ~/.ssh;chmod 700 ~/.ssh'
With the .ssh directory prepared on your Linux server you need to copy your public key to the .ssh/authorized_keys file. Then we make sure the permissions on that file allow only the deploy user read and write access:
-
scp ~/.ssh/id_rsa.pub deploy@your_linux_box.com:~/.ssh/authorized_keys
-
ssh deploy@your_linux_box.com 'chmod 600 ~/.ssh/authorized_keys'
Now you have created and deployed your SSH keypair. Using the keys you have just created you can deploy your apps effortlessly with Capistrano. Now lets modify the default port and login permissions for SSH to really lock it down. SSH into the server again, note that this time you won't be prompted for a password!
-
ssh deploy@your_linux_box.com
Edit the SSHD File:
-
sudo nano /etc/ssh/sshd_config
Edit the line that looks like this:
-
Port 22
Change it to:
-
Port 8888 # or any unused port above 1024
Edit the line that says PermitRootLogin yes and change it to:
-
PermitRootLogin no
Then save the file and quit the editor. And don’t forget to restart the SSH server daemon:
-
sudo /etc/init.d/ssh reload
From now on you won't be able to SSH into your server as root which is a good thing. You will also have to pass the port number to ssh when logging in from now on. We added this for a little more security. This is how to add the port when logging in now:
-
ssh -p 8888 deploy@your_linux_box.com
For you security buffs out there, yes I know this is security through obscurity. We will lock our server down with a firewall later on. If you are on a Mac, may I suggest you download the great terminal replacement application called iTerm. What I really like about iTerm is that you can have multiple SSH instances running in different tabs by hitting (APPLE + T). You can also add bookmarks for all of the servers you need to constantly SSH into. Once you've setup your SSH keys and added your login information to iTerm, you just click on the bookmark and you're logged into your server! Now that's convenience.
Let's go ahead and log back into our server and add some bash command aliases to make our life easier:
-
ssh -p 8888 deploy@your_linux_box.com
Let's create a bash profile:
-
nano .bash_profile
Copy and paste into the nano text editor the following commands (note that some of these commands are Debian/Ubuntu specific and won't work yet until we complete our Rails stack):
-
export PS1='\[\033[0;35m\]\h\[\033[0;33m\] \w\[\033[00m\]: '
-
alias space=' sudo find / -mount -size +2000 -exec ls -s {} \; | sort -nr | more'
-
alias os='cat /etc/issue'
-
alias free="free -m"
-
alias update="sudo aptitude update"
-
alias install="sudo aptitude install"
-
alias upgrade="sudo aptitude safe-upgrade"
-
alias remove="sudo aptitude remove"
-
alias pg='ps -afe|grep -v grep|grep'
-
alias cdapps='cd /var/www/apps'
-
alias startmg='sudo mongrel_rails cluster::start'
-
alias stopmg='sudo mongrel_rails cluster::stop'
-
alias n='nano'
-
alias sn='sudo nano'
-
alias q='quit'
-
alias ..='cd ..;ls -la | more'
-
alias cd..='cd ..'
-
alias hm='cd ~;ls -la | more'
Now exit and save the file. Type the following to load the changes we made:
-
source .bash_profile
Now try the free command to see how much memory we have available on our server (the last line is what you want to look at (the used/free columns):
-
free
If it worked you should see some output columns in your terminal window. Now go ahead and type exit and log out of your server. We're done for today. Next time we will get busy installing software on our shiny new server.

















this is awesome… many thanks. Have you ever used EC2? I’d like to have an AMI with the above configuration…
I haven’t used EC2 and wouldn’t consider it to run any serious web application. I do use s3 for backups. Below is an article that summarizes a post from Jason Hoffman of Joyent concerning EC2 issues for websites that need to scale, and one concerning the September outage EC2 had:
http://tinyurl.com/27pqor
http://tinyurl.com/yw5am9