Deployment Recipes – Deploying, monitoring and securing your Rails application to a clean Ubuntu 10.04 install using Nginx and Unicorn

This post has moved to my new blog, check it out!

This blog is being terminated :)

50 Responses to “Deployment Recipes – Deploying, monitoring and securing your Rails application to a clean Ubuntu 10.04 install using Nginx and Unicorn”

  1. Nick Kaltner Says:

    please please please use rvm instead of a vanilla ubuntu ruby install. It makes upgrading rubies and managing gems SOOO much easier.

    • Maurício Linhares Says:

      Hey Nick,

      I don’t really see any reason to use RVM in a production environment, I’d rather go for the distribution available Ruby, as they have usually been tried and tested with the other dependencies in the system and should behave correctly. I do use RVM on my dev machine and it’s a basic tool for any Ruby developer, but I like the hardened feel of the packaged ruby for my production websites.

      But that’s a matter of opinion, if you find that RVM isn’t an issue for you, go on then, it’s just a single dependency to remove from the apt-get call :)

      • Randuin Says:

        The distribution rubies are terrible. Especially if you’re deploying rails 3 apps.

        • Maurício Linhares Says:

          Any specific reason why they’re terrible, Randuin?

          Most of the times I had segfaults in production i was using a compiled or “not distributed” Ruby, so now I’m a bit more conservative about the interpreter I’m running on my machines.

          • Scott Says:

            The benefit to RVM isn’t just the Ruby binaries: there’s been some great strides in giving each separate application its own gemset, which allows a clean environment for each app to run. This, alone, is worth the minimal effort of setting up RVM.

            That said, RVM also makes it incredibly simple to upgrade/change Ruby versions, and even allows you (through the use of .rvmrc files) to automatically switch to that version of Ruby and gemset when entering each project’s directory. It’s a fantastic tool.

      • Nick Kaltner Says:

        it’s quite useful to use gemsets on different production apps, such as monit/god etc.

        Or for when you want to update the ruby, they can run side by side and you have a method to revert. Doing upgrades in production without a way to revert is asking for trouble!

        Also, ree or 1.9.2 are way better than the stock standard rubies. Ubuntu packages a ruby 1.8.7 compiled with enable-pthread, which makes it terribly slow – see here for details: https://bugs.launchpad.net/ubuntu/+source/ruby1.8/+bug/307462

  2. stJhimy Says:

    Nice one.
    Rvm in a production environment is useful in case you are running rails 2 and rails 3 applications.

    • Maurício Linhares Says:

      That’s true, i think i’ll add some notes on another blog post on how to get RVM up to run many rubies at the same time :)

      • Daniel Puglisi Says:

        That would be awesome. I’m new to rails deployment and I want to learn how to setup an Ubuntu Server 10.04 with Nginx, Unicorn and RVM.

  3. A.I. Says:

    Comipling isn’t true way. Fresh rubygems is in Ubuntu on Rails PPA: https://launchpad.net/~ubuntu-on-rails/+archive/ppa

  4. Kevin Says:

    Thanks,

    I’ve been learning RoR this week and this tutorial has really been helpful in bringing everything together as I try to put some of my scripts on my live server. It’s also a good little intro to Git, where I plan on putting some open source stuff I’ve worked on in other languages.

    Reddit <3

  5. Stephen Touset Says:

    authorized_keys2 is deprecated, and has been since 2001. http://sial.org/howto/openssh/#s6

  6. Awesome for 2010-08-26 : SRSLYAWESOME Says:

    […] Nginx, Unicorn, Ubuntu 10.04, Monit complete deployment guide. […]

  7. Eimantas Says:

    Your nginx config for virtual host contains errors. First off – access_log accepts path value OR `off’ value. There is no such value as `on’. That’s why you write this:

    And finally, as root, create the following directory:

    mkdir /usr/local/nginx

    , but do not actually explain why this is needed. If you supply decent path for `access_log’ directive – you won’t need that directory.

  8. Ivor Says:

    Hey Mauricio

    Saw this post via the ruby inside weekly mail – nice one!
    Thanks for the reference material!

  9. adun Says:

    If you used real upstart scripts instead of its sysv compatibility layer, you could skip monit entirely.

    That said monit offers more ways to check a process/service. upstart by default just checks if a process is alive, not what a webserver for example actual delivers.

  10. hari Says:

    Thanks for this guide.

    Just wondering, what are the benefits of doing this way over using Passenger/nginx?

    • Maurício Linhares Says:

      Hi Hari,

      From my local benchmarks Unicorn is being faster than Passenger and being able to run it outside of the webserver also makes it easier to configure and monitor. It also allows you to “update” your codebase and restart everything without downtime, as the old Unicorn instances are only going to be turned off once the new ones start to rise, I’m not sure how passenger handles that or if the latest version fixes this issue.

  11. hari Says:

    Hi Maurício,
    I followed your tutorial and I think I am almost there but when I access the domain, I get 500 Internal Server error and the nginx error log file says
    2010/10/13 05:18:08 [alert] 2577#0: *1015 socket() failed (24: Too many open files) while connecting to upstream, client: , server: localhost, request: “GET / HTTP/1.0”, upstream: “http://:80/”, host: “”

    nginx and unicorn seem to be running fine. Don’t where else to look.

    I tried googling but couldn’t find any answers. I am clueless, Could you please offer any suggestions?

    Thanks for your help,

    Hari

  12. hari Says:

    Fixed it!
    It came down to this:
    My app name is different from the domain name
    In the sites-available/default file, for
    upstream shop {

    I had replaced it with upstream and was seeing those errors, really strange and threw me off.
    Changed it to upstream and it started working.

    Thanks for the tutorial,
    Regards

  13. hari Says:

    Hi Maurício,
    I am finding your tutorial very useful, deploying my second one here.

    Can you give some guidance on what the nginx config changes I have to make to serve multiple domains on the same host.

    You kinda mentioned it to create separate file in sites-available folder and I created one called domain2.com and then symlinked it to sites-enabled folder but then I am stuck.
    Should I rename the default file to domain1.com?
    Should I change the nginx.conf file at all ?

    Thanks

    • Maurício Linhares Says:

      Hi Hari,

      You should not change the default file, you should create a new sile inside the sites-available folder, here’s a simple example of how you would do it if you had to answer requests to a “somedomain.com” domain:

      First thing is create a “somedomain.com.conf” file inside “/etc/nginx/sites-available/”, the name doesn’t need to be exactly like this, but I myself like to use the domain names as the name of the virtual server config files, you could name it “somedomain.conf” and it would work the same way.

      With this file created, you must configure the host this server is going to answer requests:

      server {
      # if you’re running multiple servers, instead of “default” you should
      # put your main domain name here
      listen 80 somedomain.com;

      # you could put a list of other domain names this application answers
      server_name http://www.somedomain.com;
      #add the rest of your server config, including proxies after this line
      }

      Now, with this file created and configured correctly with the proxy config, you have to tell nginx to load it, you do this by symlinking this file to the /etc/nginx/sites-enabled folder, here’s the command:

      ln -S /etc/nginx/sites-available/somedomain.com.conf /etc/nginx/sites-enabled/somedomain.com.conf

      Now you can restart nginx and this new configurarion should be available.

      • hari Says:

        Thank you for your prompt reply.
        I did the changes you mentioned and when I restart nginx, I get this error message:

        Restarting nginx: [warn]: the “user” directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:1
        [emerg]: “domain2.com” parameter can be specified for the default “listen” directive only in /etc/nginx/sites-enabled/domain2.com.conf:16
        configuration file /etc/nginx/nginx.conf test failed

        Any ideas what it is complaining about?

        nginx.conf and default files remain untouched, correct ?

        Thank you for your time.

        • Maurício Linhares Says:

          Yes, they remain untouched, it’s easier if you paste your file and you should be running nginx as root with a sudo call.

  14. George Says:

    Hi Mauricio! Thanks for great tutorial!!!
    I have a little problem with cap deploy:cold, no such file to load — initializer.
    I’m new in RoR and don’t know how to fix this problem, can you help?
    thanks

  15. Bruno Says:

    Hi Mauricio,

    Why do you don’t post about development with cocoa and ObjC?

    • Maurício Linhares Says:

      Cos right now I’m still building the text material for the Objective-C/iOS dev course, it’s taking a lot longer than I expected :(

      And unfortunately, the material is being written in portuguese, given it’s going to be used on a iOS dev course in Brazil and at this moment I don’t have plans to translate it to english, but I’ll probably post here as soon as the first batch of work si ready.

  16. Bruno Says:

    Maurício,

    Don’t have problem, I’m a brazilian guy. =]
    Se escrever os posts em português não tem problema nenhum.

    Esse curso é o que vai ter no Maré de Agilidade, em Fortaleza?
    Quando fui me inscrever tinha acabado as vagas. =/

    • Maurício Linhares Says:

      Sim, inicialmente o material vai ser apresentado no Maré, mas ele vai ser expandido pra virar um curso mesmo que deve estar disponível pela e-Genial a partir do início do ano que vem, estou trabalhando pra produzir todo o material de referência do curso e deixar tudo prontinho pra dar andamento a isso.

  17. Vincent Says:

    Hi Mauricio,

    Thank you so much for your tutorial.

    Can you tells what to change to use ruby 1.9 and mysql2 adapter?

    I know this is a basic question but for a newbie like me, it will save me a lot of trouble :)

    Vincent

    • Maurício Linhares Says:

      Hi Vincent,

      The only differences is that you would be installing ruby9 and mysql2 instead of the plain ruby 1.8 i’m installing with ruby-full, everything else should be the same.

  18. George Says:

    Hi Mauricio,

    Can you help me to fix the problem with routes? On my local machine everything’s fine, but on the server i have an error:

    The page you were looking for doesn’t exist.
    You may have mistyped the address or the page may have moved.

    Thanks

    • Maurício Linhares Says:

      Hi George,

      Is it a Rails error or something nginx is returning? If it’s a Rails error, you should probably try to run a script/server in your server to be sure that everything is running fine.

  19. George Says:

    Hi Mauricio,

    I try to run a rails s in my server, and the it’s successfully run, no errors. i try to upload documents and video to my web-site, in nging conf I add the location for my documents and video. In edit form i can upload documents and video file, this files are uploading to the server, but for some reason, the browser can’t see it and throw me 404 error, which i can find in my log file

    Started GET “/document/file/6/Vestnik.pdf” for 46.73.156.144 at
    ActionController::RoutingError (No route matches “/document/file/6/Vestnik.pdf”):

    Thanks

    • Maurício Linhares Says:

      Ok, that’s rails telling us that there’s no file in that path. Are you using a gem or anything like that to handle your uploads?

      If this file is really available, it should be at “#{RAILS_ROOT}/public/document/file/6/Vestnik.pdf”, which isn’t really nice. Uploaded files should always be at the “#{RAILS_ROOT}/public/system” folder, that’s symlinked between deployments. All your uploaded files should either be in an external service, like Amazon S3 or inside the public/system folder.

  20. George Says:

    I’m using upload_column plugin for uploading files.

  21. Montreal Web Design Says:

    You can use some of the techniques for monitoring and managing non-ruby sites i.e asp.net and php.


Leave a reply to Maurício Linhares Cancel reply