Start a Rails 4 full-featured application with uWSGI

uWSGI is a full stack application server that can act as a proxy service, process monitor and much more. In this post we will setup Feedbin, a Rails 4 application that uses Sidekiq as background jobs engine, PostgreSQL as rdbms and Elasticsearch as full-text search engine. Configuring uWSGI is quite easy, we just need to write a file!

Server configuration

Configuring a local virtual machine with Virtualbox and Vagrant is easy and out of the scope of this post, but it could help taking a look at the following links:

After you ensured ruby 2.0.0 is installed, you can install uWSGI via  rubygems:

gem install uwsgi

Clone the Feedbin repo into your machine, I cloned the repo into ~/apps:

git clone https://github.com/feedbin/feedbin.git

and comment out unicorn, capistrano-unicorn, therubyracer and foreman in the Gemfile:

# gem 'capistrano-unicorn', github: 'sosedoff/capistrano-unicorn', ref: '52376ad', require: false
# gem 'unicorn'
# gem "therubyracer", require: 'v8'
# gem 'foreman'

Feedbin takes advantage of env variables, so we add dotenv-rails to the Gemfile, this way we don’t have to export the env settings each time we run a command in console:

gem 'dotenv-rails'

dotnev-rails reads settings from the .env file:

BUNDLE_GEMFILE=/home/vagrant/apps/feedbin/Gemfile
RAILS_ENV=production
MEMCACHED_HOSTS=127.0.0.1:11121
POSTGRES_USERNAME=vagrant
DATABASE_URL=postgres://vagrant:secret@127.0.0.1:5432/feedbin_production
SECRET_KEY_BASE=yoursecretkey

And now, bundle:

bundle install --without development test

Let’s create a new database:

createdb -T template0 feedbin_production

go ahead loading schema and running the migrations (we need to load the schema because at the moment there is an error in one of the old migrations preventing the rake task to be completed correctly)

rake db:schema:load
rake db:migrate

Application setup is completed. Now we can configure uWSGI.

uWSGI

Create the uwsgi config file in config/uwsgi.ini:

[uwsgi]
# this is the application user/uid to use in our uWSGI process. uid = vagrant
# Setting master = true I'm telling uWSGI to enable the master process.
# This way uWSGI can act as an application instance monitor master = true
# Number of application instances to spawn processes = 2
# Full path of the unix socket that apache/nginx will use to speak to uWSGI socket = /home/vagrant/apps/feedbin/tmp/uwsgi.sock
# Setting this modifier to 7 will enable the ruby/rack plugin socket-modifier1 = 7
# Application root directory chdir = /home/vagrant/apps/feedbin
# Rackup file location rack = /home/vagrant/apps/feedbin/config.ru
# post-buffering and buffer-size are required by the Rack specification post-buffering = 4096
buffer-size = 25000
# load the bundle subsystem
rbrequire = rubygems
rbrequire = bundler/setup
# disable logging
disable-logging = true
# uWSGI log file location
daemonize = /home/vagrant/apps/feedbin/log/uwsgi.log
# uWSGI pid file location
pidfile = /home/vagrant/apps/feedbin/tmp/uwsgi.pid
# Start sidekiq when you start the application.
# Using smart-attach-daemon uWSGI can be used to start external services,
# and monitor them (for example it automatically restarts the daemon when you restart uWSGI)
smart-attach-daemon = %(chdir)/tmp/pids/sidekiq.pid bundle exec sidekiq -P %(chdir)/tmp/pids/sidekiq.pid -e production

As you can see we configured only one file to start both the application itself and Sidekiq.

Now we can start the application with the follow command:

uwsgi ~/apps/feedbin/config/uwsgi.ini

Our Feedbin instance is now up and running, but in order to let it work properly we need to configure nginx/apache in front of it.  If you need to install nginx you can follow the instructions at this Ubuntu community link.

Let’s now create the application configuration; below there is my nginx config file (we also need to create https self-signed certs for Feedbin):

server {
  listen 80;
  listen 443 default ssl;

  ssl_certificate /etc/nginx/certs/myfeedbin.crt;
  ssl_certificate_key /etc/nginx/certs/myfeedbin.key;


  location / {

    root /home/vagrant/apps/feedbin/public;
    include uwsgi_params;
    if (!-f $request_filename) {
      uwsgi_pass unix:///home/vagrant/apps/feedbin/tmp/uwsgi.sock;
    }
    uwsgi_param     UWSGI_SCHEME $scheme;
    uwsgi_param     SERVER_SOFTWARE    nginx/$nginx_version;
    uwsgi_param     HTTPS           on;
    uwsgi_modifier1 7;

    location ~ ^/assets/ {
      expires 1y;
      add_header Cache-Control public;

      add_header ETag "";
      break;
    }
  }

}

Restart nginx.

DONE!

Open your browser and enjoy: the application is up and running!

Appendix: Other useful uWSGI settings

RVM

If your app uses rvm you can add the following to the uwsgi.ini in order to load the rvm environment:

# load rvm
rvm-path = /home/vagrant/.rvm

Environment Variables

We used dotenv to set environment vars inside a config file, but you may prefer to set these variables directly inside uWSGI. You can do that (for our example) by adding the following to uWSGI.ini

env = BUNDLE_GEMFILE=/home/vagrant/apps/feedbin/Gemfile
env = RAILS_ENV=production
env = MEMCACHED_HOSTS=127.0.0.1:11121
env = POSTGRES_USERNAME=vagrant
env = DATABASE_URL=postgres://vagrant:secret@127.0.0.1:5432/feedbin_production
env = SECRET_KEY_BASE=yoursecretkey

The pattern is env = <name>=<value>

Final considerations

uWSGI is a powerful piece of software with a lot of interesting features like fast-routing, auto scaling, support for new plugins, alarms, mules, crontab, application caching and multiple applications management mode… oddly enough it’s so much more famous in the python world than in the ruby community.

Notes

  1. onigiri reblogged this from mikamayhem
  2. cimmino reblogged this from mikamayhem
  3. mikamayhem posted this