Edited on July 4, 2013

Once in a while, as a Ruby developer, you are faced with the situation when a product owner says, “Alright, now it’s time to make it live”. And then you probably think “I’ll be fighting with these stubborn servers for the next few days…”. If you have a very simple app or one at the early stages of its lifetime you can use one of the “no hassle deployment” platforms such as Heroku or OpenShift. But chances are you will need some custom stuff which is difficult to achieve on these kinds of platforms or you just feel better with “root” access.

You have many options for setting up Linux servers. Amongst the most popular ones are Chef and Puppet. Various hosting providers also add their own solutions for provisioning boxes (such as Stackscripts on Linode). Or you can do it “the old-school way”, manually. If you don’t need multiple machines and/or you have just a simple Rails site then provisioning tools might be an overkill. Also I believe any Ruby developer should configure the production server from scratch at least once to get familiar with this stuff and to learn where to look when troubleshooting server side problems.

Recently, I led a workshop about these things here at LLP and we decided to compile this knowledge into a blog post to share it with other Ruby developers and to have a known reference point in the future. So here it goes.

Note: the following steps were tested on Ubuntu 12.04 and 12.10. They don’t include any version-specific commands so they should also work without a problem on newer Ubuntu versions when they get released.


Let’s assume you just created a VPS box and got an email with root access. Now, login to the server. If you got access to non-root user with sudo access then switch to root with:

$ sudo -i

Set preferred editor

You’ll be configuring the machine by editing several config files. Make sure you have your preferred editor set:

$ export EDITOR=vim

Let’s also make it the default editor for future sessions also:

$ echo "export EDITOR=vim" > /etc/profile.d/editor.sh

Update apt sources and upgrade base packages

You’ll be installing packages from Ubuntu repositories. Make sure apt sources are up to date:

$ apt-get update

Now run following to install Vim editor (skip it if you prefer to use nano or


$ apt-get install vim

Set server timezone and time

To save yourself (and your app) some trouble set server’s timezone to UTC:

$ echo "Etc/UTC" > /etc/timezone

Let’s also install ntp daemon that will keep server time up to date, all the time:

$ apt-get install ntp

Add an user for your app

$ useradd -G sudo -m -s /bin/bash luna

You’ll be logging onto the server as the user “luna” from time to time to make some tweaks. Grant the user sudo access:

$ echo "luna ALL=NOPASSWD:ALL" > /etc/sudoers.d/luna
$ chmod 0440 /etc/sudoers.d/luna</div>

Copy SSH key

To avoid entering a password (for many reasons) when logging in as “luna” copy your public SSH key to server user’s ~/.ssh/authorized_keys file with the following command:

Try ssh’ing now:

$ ssh luna@luna.com You shouldn&#8217;t be asked for a password anymore.

Useful stuff

Switch to the user “luna”:

$ su - luna

Disable the installation of rdoc and ri docs for installed gems to save yourself some time:

$ echo "gem: --no-rdoc --no-ri" > ~/.gemrc

Set RAILS_ENV to production so you don’t have to type it when invoking rake:

$ echo "export RAILS_ENV=production" >> ~/.bashrc


Now, for ruby, we’ll install and use RVM to installation of ruby 1.9.3.

Switch back to root and follow the next steps.

Install RVM

Here we’ll install RVM globally (so called “system install” as opposed to “user install”).

This is handy if you want to have several apps or users on the servers.

Make sure you have the curl command installed:

$ apt-get install curl

Install a stable RVM version by piping the installation script to bash:

$ curl -L get.rvm.io | bash -s stable

Source rvm script so we don’t need to re-login:

$ source /etc/profile.d/rvm.sh

Let’s ignore RVM prompts about trusting .rvmrc files (we’ll use the default gemset

for Passenger anyway)

$ echo "export rvm_trust_rvmrcs_flag=0" >> /etc/rvmrc

RVM access for the user “luna”

Add the user luna to the rvm group:

$ usermod -a -G rvm luna

Install requirements

See what are the requirements for compiling MRI:

$ rvm requirements

Most likely it is in the following list of packages:

$ apt-get install build-essential openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison subversion

Install Ruby

Now, install ruby via RVM:

$ rvm install 2.0.0

Make installed ruby a default

Make it a default for all new shells:

$ rvm --default use 2.0.0

Nginx + Passenger

As far as a webserver is concerned, the combo of Nginx + Passenger works well in most cases.

Install the passenger gem

$ gem install passenger

Install Nginx via the passenger gem

First install dependencies for Nginx/Passenger:

$ apt-get install libcurl4-openssl-dev

Now compile it:

$ passenger-install-nginx-module

Just follow the instructions to compile and install nginx.

Create boot service (upstart)

The upstart script for Nginx will be used for starting/stopping nginx via the command line and will make sure nginx starts on system boot.

Download the script:

$ curl https://gist.github.com/sickill/2492523/raw/d1ecb87e9eba9e59ddd44d3c3aaf6c3c52b16374/nginx.conf

Start nginx:

$ start nginx

And check if it works by looking at the response:

$ curl localhost

“Welcome to Nginx” means that everything is fine.


Now we need to create a Virtual Host config for the luna app, replace the default

server block with the following:

# /opt/nginx/conf/nginx.conf

server {
listen 80;
server_name www.luna.com luna.com;
root /home/luna/current/public; &#35; passenger_enabled on;

Restart Nginx:

$ restart nginx

And confirm that it restarted properly:

$ curl localhost

You should get the 404 page due to the fact that our app is not running yet.


Install the MySQL server via apt:

$ apt-get install mysql-server libmysqlclient-dev

Create a project database (you will be asked for the mysql root password you set when running the previous installation command):

$ echo "create database luna_production" | mysql -u root -p

And grant access to the user luna:

$ echo "grant all on luna_production.* to luna@localhost identified by 'luna123'" | mysql -u root -p


Let’s use Capistrano for deploying new releases of the “luna” app.

Note: All of the commands in this section are meant to be run on your local machine inside the Rails project directory (unless otherwise stated).

Add capistrano to the bundle

First add the following to your app’s Gemfile:

group :development do
  gem 'capistrano'
  gem 'rvm-capistrano'

The last one nicely integrates capistrano with RVM.

Install new gems:

$ bundle

Generate skeleton capistrano config files

$ bundle exec capify .

You should have Capfile and config/deploy.rb files now.

Edit Capfile

Make the file contents look like this:

load 'deploy'
load 'deploy/assets'
load 'config/deploy'

load ‘deploy/assets’ handles assets compilation in Rails 3. If you’re deploying a Rails 2 application just remove this line.

Edit config/deploy.rb

First, you should fill the variables with your application name, repository and web server name. Then find the commented out block of code that’s related to Passenger. Just uncomment it.

Then make sure you have following lines in the file:

require 'rvm/capistrano'
require 'bundler/capistrano'
ssh_options&#91;:forward_agent&#93; = true
set :deploy_via, :remote_cache
set :use_sudo, false
set :user, "luna"
set :deploy_to, "/home/luna"
set :rails_env, "production"
set :rvm_type<, :system
set :keep_releases, 3
after "deploy:restart", "deploy:cleanup"
namespace :deploy do
  desc "Symlink shared/* files"
  task :symlink_shared, :roles =&gt; :app do
    run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
after "deploy:update_code", "deploy:symlink_shared"

Allow capistrano prepare directory structure on the server

$ bundle exec cap deploy:setup

Copy the example database config file to the server:

First create a config directory inside the shared directory:

$ ssh luna@luna.com mkdir -p ~/shared/config

Copy the file:

$ scp config/database.yml.example luna@luna.com:~/shared/config/database.yml

Now set proper values in database.yml on the server:

$ ssh luna@luna.com vim shared/config/database.yml

And deploy for the first time:

$ bundle exec cap deploy

Once you have the application code on the server log in there and prepare db structure:

$ ssh luna@luna.com

The following happens in a remote shell

$ cd current
$ bundle exec rake db:setup

Finally, deploy just to make sure everything works:

$ bundle exec cap deploy


Create the /etc/logrotate.d/luna file with following content:

/home/luna/app/shared/log/*.log {
rotate 30

That will tell logrotate to rotate log files daily, compress them, keep for 30 days and don’t choke when file is missing. copytruncate is important here as it will make sure the log file currently used by the Rails app is not moved but truncated. That way the app can just keep on logging without reopening log file.

Don’t forget about this, if you manage production box yourself. And do it when you initially setup the box, not “later”. “Later” often means “when the app is down due to not enough disk space”. Srsly.


Ubuntu comes with a decent firewall management tool called ufw. Install it:

$ apt-get install ufw

Now set the default firewall policy to “deny”:

$ ufw default deny

And allow connections to the services we want to expose to the world:

$ ufw allow ssh/tcp
$ ufw allow 80/tcp
$ ufw allow 443/tcp

Finally, enable firewall:

$ ufw enable

Your production environment is safer now.

Mail server (MTA)

There are many offerings for a SMTP service that also brings in some additional features like email opening tracking, link click tracking and whatnot. If you just need the plain “send message and forget” functionality you may use Postfix MTA.

Install it by:

$ apt-get install postfix heirloom-mailx

Thanks to the firewall rules from the previous section you don’t need to worry about spammers using your server for sending their spam. They won’t be able to connect to your Postfix daemon from outside the machine.


For basic system monitoring the easiest thing you can do is to install monit:

$ apt-get install monit

Open /etc/monit/monitrc in an editor and adjust the default config to suit your needs.

By default it monitors CPU usage, memory usage, disk usage and several other system-level components.

If you’ve been using god for monitoring your app processes then you may consider using monit also for this task as it’s a much simpler tool for the job.

That’s it!

Great, you have now fully configured an Ubuntu server ready to serve your awesome Ruby on Rails application. I hope this tutorial made you realize that this task is not as hard as you thought. Now, after you went through all of this manually try building a set of Chef cookbooks that accomplish the above tasks automatically (and repeatably) for you.

Join the Lunar crew!

Mirek Wozniak January 23, 2013

Lunar Logic is hiring! Risky intergalactic voyages take their toll. Astronauts get sucked into wormholes, meteors break off whole sections of space stations and the encounters with alien species are not always as friendly as we’d like them to be.

That’s why we’re in need of fresh blood.

We’re looking for Ruby developers with at least 2 year experience in programming that speak communicative English.

Yes, that’s it. No fluffy marketing nonsense, no-nothing!

Well, you can earn extra bonus points for Scrum experience (planning space walks), being involved in the community (contact with the aliens), open source contribution (tweaking the on-board instruments) and talks/presentations at events (promoting the idea of space travel).

What awaits you? Breathtaking adventures, unforgettable memories and thrilling projects! Along with  flexible working hours, office in the very centre of Krakow and a rich range of extra benefits, including automated health system, free access to various sport and leisure facilities as well as available services of well-trained foreign language teachers.

Web apps won’t make themselves. Check our jobs page for a more elaborate offer. :)

Rails bot, a tiny retweeting assistant.

Kuba Suder January 21, 2013

The idea

Retweeter bot in action! The are a lot of people in the Ruby/Rails community that I’d like to follow. However, in order to read their interesting tweets I’d also have to agree to read all the other things they tweet, and then I wouldn’t do anything else than read tweets all day.

Basically, I want to read this:

But not this:

(sorry, Aaron…)

What I need is someone that would follow all these people, read all their tweets and retweet only what seems important. This bot is my attempt at creating such filter.

How it works

The basic idea was that the best tweets get retweeted a lot, so I made the bot select tweets with a high number of retweets. Adding favorites improved things further, because a lot of tweets get many favorites but not many retweeets (especially some useful but not funny tweets from @ruby_news or @rubyflow – the funny ones get retweeted the most). I’ve ignored retweets of tweets by people outside the list, because almost all of them were off topic.

Now I had most of the interesting tweets marked to be retweeted, but most of the top tweets were still not relevant – funny tweets about random things, tweets about politics, current news, Apple, Microsoft, startups, religion, etc. So then I’ve added a keyword whitelist – I went through the top tweets and I’ve prepared a list of keywords that would only match the tweets I’d like to see retweeted.

I’ve also made the minimum number of retweets+favorites depend on the author – those with a high number of followers get much more retweets on average, so a post with 30 retweets by @spastorino (3871 followers) will usually be more interesting than a post with 30 retweets by @dhh (72141 followers).

The end result is that even though some good tweets are ignored and some off topic tweets get retweeted (e.g. this Aaron Patterson’s tweet got through because the bot thought that the word “rest” was about REST), the filter works surprisingly well in most cases. It should retweet about 4 tweets per day on average, which sounds like an acceptable number. I’ll be checking the results from time to time and making tweaks to the keyword list and the algorithm to make sure the bot makes the right choices.

Check out the sample below and follow @rails_bot if you like it. If you’d like to learn more about how it works (and maybe help me improve it), see the source code on GitHub.

Enjoy your cleaner twitter feed!

Tweets by @rails_bot

Why we needed a new blog?

Mirek Wozniak January 14, 2013

New Lunar Logic blog! Liftoff! We have a liftoff…

You can’t even dream of travelling to distant galaxies when all you’ve got is an old space shuttle. That’s why we’ve prepared the new Lunar Logic website. Our blog needed a serious overhaul, too.

It isn’t just about the looks – we’re going to mainly speak about technical stuff now, as well as get excited about the events we went to. Add some news and a bit of fun to top it off.

But there’s another reason for getting the new image. Lunar crew has just strengthened in numbers.

Let’s cut the chatter. Meet Rafael.

Rafael Caricio, our new developer

Rafael Caricio is our newest recruit. This open source enthusiast flew directly to our office from hot Brazil. He seems to have friends everywhere – we thought he would need some time to familiarise with the new environment, but he seems like a good Ruby gem – seamlessly joining with the existing structures here in Krakow.  Well, he was a bit confused about the snow, but he suited up quickly to meet the cold :)

Rafael is a busy man. Before coming to Lunar he started breeding tiny robots for GitHub Game Off 2012. As he put it:

Me and my co-workers  decided to create a project where people would be able to program and have fun seeing some animations. The idea came from Robocode (the original Java version), but we wanted to create it from the ground up. And we did. One of us took care of the engine and the rest of us for the website. We talked to a designer and she accepted the challenge of designing the game website. The coding itself took two weeks. We’ve been very surprised by the amount of attention it received, so we’ve decided to go ahead with the project and work on a completely new version trying to archive the feature requests from our players. The current, rewritten version of the game is more robust and has Python in the backend.

What is more? Rafael is an avid Python programmer and seems to be attracted by interesting events. DjangoDash? Node Knockout? Rails Rumble? You name it. He likes to work together with others and loves to share his knowledge. Have I told you that he’s busy? He helped with open-source Thumbor (loved by Square or Le Figaro), Provy, a provisioning tool for Python, alternative to Puppet or PIP, Python package management tool. And it’s just a beginning of the list of Rafael’s deeds.

So, what’s next? Mr. Caricio has just found himself a nice flat and is still amazed by the snow and freezing -1 degree Celsius. Luckily, our office is prepared for nature’s onslaught – we’ve got hot tea and lemon.

Worry not, Rafael!

Sagrada Familia at Baruco 2012 Barcelona is truly a beautiful city. Our lunar expedition was amazed by its thriving narrow streets, colorful nightlife and exquisite cuisine full of strange sea creatures. But, surprisingly, these weren’t the reasons we came here. We came here to attend BaRuCo, to listen about Ruby, talk about Ruby, and meet fellow Rubyists from all over the world. How was it then, you probably wonder? Read on!

Marek: the first thing I noticed about the conference was it’s venue – a science museum. Whoever came with the idea of putting a bunch of nerds in a building full of bizarre contraptions demonstrating various laws of physics was a genius. I was eagerly awaiting the end of the talks each day just to see it all! Ok, it isn’t exactly true, because the talks were great.

I especially liked the talks by Github’s Scott Chacon and Zach Holman, who presented ways of getting your work done more efficiently, respectively by solving the most basic problems better than before, and by automating every tedious developer task that can be automated. Paolo Perrota did a great job by humorously summarizing the history of software engineering and showing its impact on modern developers.

Among the more technical talks I enjoyed ones by Gary Bernhardt and Xavier Noria most. The first one described the structure of modern web frameworks, ways of enhancing it, and pros and cons of every approach. The other one demystified the magic of Rails autoloading mechanisms.

Most of the lightning talks were also very interesting, with topics ranging from zsh tips and tricks to a game of go to how perseverance is more important than talent.

I really enjoyed the first Barcelona Ruby Conference, and I’m looking forward to the second one :)

Phillip: BaRuCo was hosted in the CosmoCaixa museum in Barcelona, which made for a very interesting two days because when the talks were over there was still much to do, although unrelated to the conference itself.

Baruco 2012 Macbook

The conference started out with a very good keynote by Scott Chacon, co-founder of GitHub, with a topic that was not technical, but rather a point about getting work done and creating software that solves specific problems by getting back to the basic principles set forth by the company or project, respectively. The remainder of the day had many enthusiastic and passionate speakers, most notably Gary Bernhardt with his talk about deconstructing the usual controller in MVC to smaller more single purpose parts, Anthony Eden with his talk about the protocols used in the programming community, and Paolo Perrotta with his very humorous, very interesting look into the history of Software Engineering and how we have come to Agile methodologies.

After the main speakers there was a chance for the attendees to give lightning talks that were time boxed to 5 minutes. These were very interesting, ranging from quick talks about helpful tips on apps to user, to a talk about the ancient board game Go, to a guy telling a story about hope. Let me elaborate on this guy and his story, as he reached his 5 minutes mark and was buzzed to stop, but received a wave of applause to keep telling his tale. Hope was the point of his talk, in that he was an average developer, like most of us are, and he made software that actually helped people and was a relative success. This story definitely resonated with me, and, I assume, most of the attendees.

The second day had talks that seemed to be less enthusiastic but ended on a much stronger note than the day began. All in all, I think this was a very nicely organized conference with quite a few good talks. The only really complaints I have is that the wifi could not handle this many developers in one room, and at the beach party there needed to be more beer.