A somewhat secure Debian server with nginx, Passenger, rbenv for hosting Ruby on Rails with mail support and deployment with Capistrano Setting up a VPS for personal projects

Basically this is a technical note to myself, in case I need to setup another server for running yet another personal Ruby on Rails project. And don’t worry, I’m not going to replicate all nice guides out there, just filling in the gaps.

So let’s start with the list of bookmarks I follow as a start. Note that in these tutorials mostly a user is used named ‘deploy’. Typically I create a user per project and name databases etc. accordingly.

  1. Get security right first: My first 5 minutes on a server or essential security for Linux servers
  2. Then I get Rails up and running with this how to install Ruby on Rails with rbenv on Debian
  3. (in case you want to use the server as your remote git repo too) Git setting up a remote repository and doing an inital push
  4. Continue with the Passenger install instructions

Ok. Now following it up with some more Debian specific/own notes that I didn’t find well covered in other guides (because they rely on the ugly rvm, not use nginx, or not with passenger and capistrano or just leave out some details that I found missing.

A somewhat secure Debian server with nginx, Passenger, rbenv for hosting Ruby on Rails with mail support and deployment with Capistrano

A photo of some servers in use by Wikipedia, created by Wikimedia Foundation and released under a creative commons share alike license

Installing a ruby version

We want to have of course a recent version of ruby running (otherwise we could’ve just used 1.9 that is in de debian repositories) and we want to prepare for Rails so we want bundler (there may be a later version than Ruby 2.1.0, get what you want). So we execute the following:

rbenv install 2.1.0
rbenv global 2.1.0
gem install bundler 

Setting up nginx

Create a file inside die available sites directory of nginx

 vim /etc/nginx/sites-available/{sitename}

(I typically use the full domainname as filename)

and fill it up with something like

server {
	listen 80;
	server_name example.com;
	root /home/deploy/public/example.com/current/public;
	passenger_ruby /home/deploy/.rbenv/shims/ruby;
	passenger_app_env production;
	passenger_enabled on;
}

then symlink it in sites-enabled: ln -s ../sites-available/{sitename} and restart nginx: service nginx restart

Wait for a sec. We haven’t got anything there right? Check. Let us fix capistrano to.

Setting up capistrano for easy deployment

Follow installation instructions at https://github.com/capistrano/rails

Add this line to your application’s Gemfile:

gem 'capistrano-rbenv'
gem 'capistrano-bundler'
gem 'capistrano-rails'
gem 'capistrano-passenger'
gem 'capistrano-nvm', require: false
gem 'capistrano-yarn'

Run cap install STAGES=staging,production and add the following line to Capfile (in your project’s root, where the Gemfile is as well)

# ...
# Includes tasks from other gems included in your Gemfile
#
# For documentation on these, see for example:
#
#   https://github.com/capistrano/rbenv
#
require 'capistrano/rbenv'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano/yarn'

...

And fill up config/deploy.rb with something along the lines of this (make sure you replace deploy as the remote user if changed and set example.com correctly. Also the repo_url may be totally different (I’m storing the source at the same server, your opinions may vary, but it is good enough for my solo projects)

set :rbenv_type, :user # or :system, depends on your rbenv setup
set :rbenv_ruby, File.read(File.expand_path("../.ruby-version", __dir__)).strip
set :rbenv_roles, :all # default value
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
set :rbenv_map_bins, %w{rake gem bundle ruby rails}

set :remote_user, 'deploy'
set :application, 'example.com' #domain

set :repo_url, "#{fetch(:remote_user)}@#{fetch(:application)}:/home/#{fetch(:remote_user)}/taggedhours.git"

# Default deploy_to directory is /var/www/my_app
set :deploy_to, "/home/#{fetch(:remote_user)}/public/#{fetch(:application)}"

# Default value for :linked_files is []
set :linked_files, %w{config/secrets.yml config/database.yml}

# Default value for linked_dirs is []
set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system public/upload}


namespace :deploy do
  desc 'Restart application'
  task :restart do
    on roles(:app), in: :sequence, wait: 3 do
      execute :touch, release_path.join('tmp/restart.txt')
    end
  end

  after :publishing, :restart

  desc 'Show logs'
  task :log do
    on roles(:app), in: :sequence, wait: 5 do
      execute :tail, " -n 100 #{shared_path}/log/production.log"
    end
  end
end

Also check the config of config/deploy/production.rb if everything is set there properly.

Just to be sure, restart nginx: service nginx restart on the server and then try cap production deploy from your source dir.

And when you encounter errors, watch tail -f -n 100 /var/log/nginx/error.log or if you see already a rails error, you may run cap production deploy:log from your development machine.

Make your applications mail

The easiest way to enable mailing in your apps is to have something compatible with sendmail working. I use Postfix for that:

apt-get install postfix

Select internet site and set the FQDN accordingly (your site’s domainname). Run a small test:

mail your-email-account@example.com

and type in the subject, hit Enter, type some test message and end with a last line that features only a dot (‘.’) and hit Enter twice. Check your mail at your-email-account@example.com and you should’ve received a mail.

Bonus. Set up PostgreSQL

Ok, almost done, right? You don’t want to use sqlite for projects that write a lot/have concurrent users (execute every line by line, we’re changing users and interpreters here ;)):

sudo su
apt-get install postgresql postgresql-client libpq-dev
su postgres
psql
CREATE USER deploy WITH PASSWORD 'mypguserpass';
CREATE DATABASE mypgdatabase OWNER deploy;
\q

Just give the deploy user no additional rights, and note that the libpg-dev package is added so the gem ‘pg’ will install properly.

Then make sure your your database.yml in public/example.com/shared/config looks something like this:

production:
  username: deploy
  password: mypguserpass
  adapter: postgresql
  encoding: unicode
  database: mypgdatabase
  host: localhost
  pool: 5
  timeout: 5000

More installing on PostgreSQL you’ll find on this Debian guide.

And some other things you may want to do

Done?

As said, I’m not a server administrator. But I do think anyone should be able to set up a server, and hence this guide (also as a reference for myself). I would like to get better though and welcome any suggestions. You’ll find me on twitter: @murb

Op de hoogte blijven?

Maandelijks maak ik een selectie artikelen en zorg ik voor wat extra context bij de meer technische stukken. Schrijf je hieronder in:

Mailfrequentie = 1x per maand. Je privacy wordt serieus genomen: de mailinglijst bestaat alleen op onze servers.