Ghost Deployment on EC2 with nginx, capistrano and PM2
- You need to create an AWS EC2 server (Ubuntu 14.04) with add an EBS.
- Make sure you have port 80 opened in the inbound section of the security groups.
- Follow instructions to make your server secure. (optional)
- I have mounted my EBS at /mnt/data and I am using /mnt/data/blog/current as the root directory for the ghost application.
- Install nginx
sudo apt-get install nginx
- Create cache directories
sudo mkdir /var/cache/nginx
sudo chown www-data:www-data /var/cache/nginx
- Here’s my nginx config. It’s pretty barebones just to make stuff work. You can copy it as it is or make more advanced changes to it.
sudo vim /etc/nginx/nginx.conf
user www-data;
worker_processes 4;
pid /run/nginx.pid;
events {
worker_connections 768;
# multi_accept on;
}
http {
sendfile on;
keepalive_timeout 65;
types_hash_max_size 2048;
include mime.types;
default_type application/octet-stream;
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=one:8m max_size=3000m inactive=600m;
proxy_temp_path /var/tmp;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 1000;
upstream ghost_upstream {
server 127.0.0.1:2368;
keepalive 64;
}
server {
listen 80;
server_name code.anirvan.me;
location / {
root '/mnt/data/blog/current';
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header Connection "";
proxy_http_version 1.1;
proxy_cache one;
proxy_cache_key ghost$request_uri$scheme;
proxy_pass http://ghost_upstream;
}
}
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
- Reload nginx
sudo /etc/init.d/nginx restart
-
Install node version manager on the server and install node v0.10.42.
-
Install pm2 globally on the node server
-
Install ghost to your local machine. Follow the instructions here.
-
Initiate a git repo
git init
Make sure your you ignore the files not required
content/images/*
content/data/*
node_modules/
- Add capistrano to your project to help with deployments.
I am using ruby 2.1.5 using rvm in my local environment
The Gemfile looks like this
ruby '2.1.5'
source 'https://rubygems.org'
gem 'bundler'
gem 'capistrano'
gem 'capistrano-npm'
Initialize capistrano
cap install
Only the production environment was of relevance for me, so I deleted config/deploy/staging.rb
The config/deploy/production.rb should looks like this
server "YOUR SERVER IP", user: "ubuntu", roles: %{web}
set :scm, :git
set :branch, "master"
set :application, "YOUR_APPLICATION_NAME"
set :repo_url, "YOUR_GIT_REPO"
set :deploy_to, "/mnt/data/blog"
set :user, 'ubuntu'
set :app_command, 'start.sh'
set :process_name, 'node_server_code_blog'
The config/deploy.rb looks like this
set :keep_releases, 5
namespace :deploy do
after :publishing, :install_packages do
on roles(:web) do
within current_path do
execute :npm, :install, '--production'
end
end
end
after :install_packages, :restart do
invoke 'pm2:restart'
end
end
Add a file /lib/tasks/pm2.cap. This basically takes care of monitoring your node application.
require 'json'
namespace :pm2 do
def app_status
within current_path do
ps = JSON.parse(capture :pm2, :jlist, fetch(:process_name))
if ps.empty?
return nil
else
return ps[0]["pm2_env"]["status"]
end
end
end
def restart_app
within current_path do
execute :pm2, :restart, fetch(:process_name)
end
end
def start_app
within current_path do
execute :pm2, :start, fetch(:app_command) --name=fetch(:process_name)
end
end
desc 'Restart app gracefully'
task :restart do
on roles(:web) do
case app_status
when nil
info 'The application is not registered'
start_app
when 'stopped'
info 'The application is not running'
restart_app
when 'errored'
info 'The application is in an erroneous state'
restart_app
when 'online'
info 'The application is already running'
restart_app
end
end
end
end
- Add capistrano-npm and pm2.cap to the Capfile
...
require 'capistrano-npm'
import 'lib/tasks/pm2.cap'
...
Add a start.sh script to your project root
#!/bin/bash
cd /mnt/data/blog/current
npm start --production
-
Make sure your latest changes are present in the master branch of your git repository
-
Deploy from your local environment
cap production deploy
- If there are no errors your ghost blog should be available at the public ip of your EC2 instance