Deploy Discourse to an Ubuntu VPS using Capistrano

(David Celis) #1

UPDATE: I strongly suggest you use the Docker-based installation that is more officially supported. If you reaaaaaally want to do this instead, then read on.

I read through @baus’s thread for throwing Discourse onto an Ubuntu server, but I really wanted to deploy it the same way I deploy all of my own apps: with Capistrano.

So I’ve written up this blog post to help others who want to follow the same path. I hope it helps you guys! This post should help new Discourse users hit the ground running on an Ubuntu 12 or 13 VPS with zero-downtime deployments using Capistrano.

If you guys have any issues, please let me know here and I’ll edit the guide ASAP. Thanks!

Organiziaton of documentation for installs - docker vs. non-docker / official vs. unofficial
"Down for Maintenance" page
(knwang) #2

Nobody has commented on this yet? This is amazing! It took me quite a while to figure out everything… I wish I had this when I set up discourse…


Great post!
Thank you!

(The Crab) #4

Awesome post. Now I can move on with this.


My two cents.

I think it’s better to have a secret_token on an environment variable, so you don’t need to modify the code.

Also, there is a recommendation by Sam to use a differnt library to memory allocation. I don’t know exactly the details about that, but maybe is usefull to check if this helps to.

(Sam Saffron) #6

I recall adding the secret token file to .gitignore so its ok to edit it, but environment var is fine as well. The library we use is tcmalloc TCMalloc : Thread-Caching Malloc.

(David Celis) #7

I’m okay with modifying a file or two, like .gitignore. Having an occasional merge conflict in .gitignore isn’t terribly annoying for me.

Of course, if it’s a private project, you could keep secret_token.rb in version control and not worry too much about it (and I doubt that file would change much, so I’d worry even less about merge conflicts there).

(David Celis) #8

What’s the process for using tcmalloc with Ruby/Rails/Discourse? I found the download of google’s perf-tools, but is this something that requires a patch while building Ruby?

(Robbie Straw) #9

One question about your approach:

Does Capistrano handle starting your processes on init at all?

Is it possible to write an init script [on the server running Discourse] that calls cap:deploy to start and stop the server?

I’m not familiar w/ Capistrano, and from your guide it’s not clear if you can call cap deploy from the server, or if it has to be called from a developer’s box.

I agree that Capistrano is a great “rubyish” tool, but I’d feel more comfortable having Discourse start when the server starts for two reasons:

  1. Uptime SLAs are great and all, but outages happen. If/when the server comes back online, it’d be nice for Discourse to do the same
  2. As I’m sure you’ve seen: Digital Ocean lets you image machines and deploy from those images. (Which is fast, gotta love SSDs.) – It’d be nice to spin up extra instances and have them up and running without even logging into the box. Doing something like this behind a reverse proxy? You could easily scale-out your network under times of high load.

Great writeup though. I’ve never used Capistrano before and it was really easy to follow along.

(David Celis) #11

You’re right, Discourse wouldn’t start on a server reboot in this case. You’d have to run cap deploy:start from your local machine (all Capistrano commands are run locally from the repository).

You could pair my approach with an init.d script that would essentially run what the Capistrano deployment commands are running.

(Chad Gregory) #12

I am currently at the “bundle install” step and I have followed the guide to a tee other than changing the username of course but it is telling me…

“bundle: command not found”

and yes I installed it with the command he provided

(David Celis) #13

When you’re setting up discourse, that should be done locally. Presumably, you’d have Ruby and bundler installed. I’ll update the guide.

(David Celis) #14

Turns out I made a mistake. I was under the impression from the rbenv installation guide that ~/.profile was the correct place to put rbenv’s initialization statement, rather than ~/.bash_profile. Turns out ~/.bash_profile is the one that is correctly being loaded, so I’ll correct it (again).

(colin) #15

Hey @davidcelis,

Thanks so much! I had put together some capistrano scripts previously. Being a relative n00b at Capistrano, they were pretty fragile. I was also trying to use Bluepill which didn’t seem to work so well.

I tweaked my setup with changes from your deploy.rb and it works flawlessly now. Thanks so for sharing your work.


(David Celis) #16

Glad it worked so flawlessly for you! Setting up servers has always been the bane of my existence as a web developer. I’d rather write the code than set up the infrastructure to run the code. And I always forget exactly what I need to do to get a server set up to run my web apps. I should just learn Chef. Ugh.

(Luke) #17

Is that safe deploy without using www-data group.

(David Celis) #18

Why wouldn’t it be? nginx is still run using www-data. Why would there be an issue using a different user to do the actual deployment?

(Luke) #19

I do it with your blog.when I run “cap deploy:setup” the first time, it seems that the deploy user should be in the sudo group,so I add the deploy user to the sudo group.And then I run “cap deploy:setup” agagin,this time I got the error for the absence of current folder。

** [out ::] sh: 1: cd: ** [out ::] can’t cd to /home/apps/discourse/current ** [out ::]
command finished in 7ms failed: “env RBENV_ROOT=/home/apps/.rbenv PATH=/home/apps/.rbenv/shims:/home/apps/.rbenv/bin:$PATH sh -c ‘cd
/home/apps/discourse/current && bundle install’” on

(David Celis) #20

Did cap deploy:setup correctly create the directories in /home/apps ?

(Luke) #21

other directories such as releases ,shared are created,but current.
If I manually create the current folder, then “cap deploy:setup” will enter the current folder and run “bundle install”,but the current folder is empty,so the error poped again.