Create droplet of your liking (ubuntu 12.04 x32) Use an xx.04 LTS version
On Digital Ocean, create a DNS entry for your server (xyz.com)
Make sure it has NS records that use digital oceans nameservers
NS1.DIGITALOCEAN.COM.
NS2.DIGITALOCEAN.COM.
NS3.DIGITALOCEAN.COM.
Setup a generic A record with your IP address
@ 123.123.123.123
Setup useful subdomains as A records
www 123.123.123.123 mail 123.123.123.123 smtp 123.123.123.123
Setup an MX record
10 mail.xyz.com.
(note the . at the end)
Setup an SPF record (type = TXT)
@ "v=spf1 ip4:123.123.123.123 ~all"
ssh to root in terminal with your server ip
ssh [email protected]
Add ssh fingerprint and enter password provided in email
Change password
passwd
Create new user
adduser deploy
Set new users privileges
visudo
Find user privileges section
# User privilege specification
root ALL=(ALL:ALL) ALL
Add your new user privileges under root & cntrl+x then y to save
deploy ALL=(ALL:ALL) ALL
Configure SSH
nano /etc/ssh/sshd_config
Find and change port to one that isn't default(22 is default: choose between 1025 ..65536)
Port 22 # change this to whatever port you wish to use
Protocol 2
PermitRootLogin no
PasswordAuthentication no ChallengeResponseAuthentication no
Add to bottom of sshd_config file after changing port (cntrl+x then y to save)
UseDNS no
AllowUsers deploy
Reload ssh
reload ssh
Don't close root! Open new shell and ssh to vps with new username(remember the port, or you're locked out!)
ssh -p 1026 [email protected]
Update packages on virtual server
sudo apt-get update
sudo apt-get install curl
install latest stable version of rvm
curl -L get.rvm.io | bash -s stable
NOTE: There is currently (7/23/13) a problem with RVM 1.21.13 that was causing it report problems with the PATH that didn't exist. This blows up capistrano later. The solution is
rvm get 1.21.12
load rvm
source ~/.rvm/scripts/rvm
install rvm dependencies
rvm requirements
Install ruby 2.0.0
rvm install 2.0.0
Use 2.0.0 as rvm default
rvm use 2.0.0 --default
install latest version of rubygems if rvm install didn't
rvm rubygems current
install rails gem
gem install rails --no-ri --no-rdoc
Install postgres
sudo apt-get install postgresql postgresql-server-dev-9.1
gem install pg -- --with-pg-config=/usr/bin/pg_config
Create new postgres user
sudo -u postgres psql
create user deploy with password 'password';
alter role deploy superuser createrole createdb replication;
create database projectname_production owner deploy;
Install git-core
sudo apt-get install git-core
I ultimately needed some other low level libraries for Nokogiri and Imagemagick to build
sudo apt-get install libxslt-dev libxml2-dev
sudo apt-get install imagemagick libmagickcore-dev libmagickwand-dev
Install bundler
gem install bundler --no-ri
setup nginx
sudo apt-get install nginx
nginx -h
cat /etc/init.d/nginx
/etc/init.d/nginx -h
sudo service nginx start
cd /etc/nginx
On the development machine, edit the Gemfile to include unicorn.
Gemfile
group :production do gem 'unicorn' end
then create placeholders for the confirmation files
touch config/unicorn.rb
touch config/unicorn_init.sh file
touch config/nginx.conf
chmod +x config/unicorn_init.sh
config/nginx.conf (change projectname and username to match your directory structure!)
upstream unicorn {
server unix:/tmp/unicorn.projectname.sock fail_timeout=0;
}
server {
listen 80 default deferred;
# server_name example.com;
root /home/deploy/apps/projectname/current/public;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri @unicorn;
location @unicorn {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://unicorn;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
config/unicorn.rb
root = "/home/deploy/apps/projectname/current"
working_directory root
pid "#{root}/tmp/pids/unicorn.pid"
stderr_path "#{root}/log/unicorn.log"
stdout_path "#{root}/log/unicorn.log"
listen "/tmp/unicorn.projectname.sock"
worker_processes 2
timeout 30
# Force the bundler gemfile environment variable to
# reference the capistrano "current" symlink
before_exec do |_|
ENV["BUNDLE_GEMFILE"] = File.join(root, 'Gemfile')
end
config/unicorn_init.sh
#!/bin/sh
### BEGIN INIT INFO
# Provides: unicorn
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Manage unicorn server
# Description: Start, stop, restart unicorn server for a specific application.
### END INIT INFO
set -e
# Feel free to change any of the following variables for your app:
TIMEOUT=${TIMEOUT-60}
APP_ROOT=/home/deploy/apps/projectname/current
PID=$APP_ROOT/tmp/pids/unicorn.pid
CMD="cd $APP_ROOT; bundle exec unicorn -D -c $APP_ROOT/config/unicorn.rb -E production"
AS_USER=deploy
set -u
OLD_PIN="$PID.oldbin"
sig () {
test -s "$PID" && kill -$1 `cat $PID`
}
oldsig () {
test -s $OLD_PIN && kill -$1 `cat $OLD_PIN`
}
run () {
if [ "$(id -un)" = "$AS_USER" ]; then
eval $1
else
su -c "$1" - $AS_USER
fi
}
case "$1" in
start)
sig 0 && echo >&2 "Already running" && exit 0
run "$CMD"
;;
stop)
sig QUIT && exit 0
echo >&2 "Not running"
;;
force-stop)
sig TERM && exit 0
echo >&2 "Not running"
;;
restart|reload)
sig HUP && echo reloaded OK && exit 0
echo >&2 "Couldn't reload, starting '$CMD' instead"
run "$CMD"
;;
upgrade)
if sig USR2 && sleep 2 && sig 0 && oldsig QUIT
then
n=$TIMEOUT
while test -s $OLD_PIN && test $n -ge 0
do
printf '.' && sleep 1 && n=$(( $n - 1 ))
done
echo
if test $n -lt 0 && test -s $OLD_PIN
then
echo >&2 "$OLD_PIN still exists after $TIMEOUT seconds"
exit 1
fi
exit 0
fi
echo >&2 "Couldn't upgrade, starting '$CMD' instead"
run "$CMD"
;;
reopen-logs)
sig USR1
;;
*)
echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>"
exit 1
;;
esac
Add capistrano and rvm capistrano to gemfile
gem 'capistrano'
gem 'rvm-capistrano'
Create capfile & config/deploy.rb files
capify .
deploy.rb (remember to change the port to whatever number you used for ssh)
require "bundler/capistrano"
require "rvm/capistrano"
server "123.123.123.123", :web, :app, :db, primary: true
set :application, "projectname"
set :user, "deploy"
set :port, 1026
set :deploy_to, "/home/#{user}/apps/#{application}"
set :deploy_via, :remote_cache
set :use_sudo, false
set :scm, "git"
set :repository, "[email protected]:username/#{application}.git"
set :branch, "master"
default_run_options[:pty] = true
ssh_options[:forward_agent] = true
after "deploy", "deploy:cleanup" # keep only the last 5 releases
namespace :deploy do
%w[start stop restart].each do |command|
desc "#{command} unicorn server"
task command, roles: :app, except: {no_release: true} do
run "/etc/init.d/unicorn_#{application} #{command}"
end
end
task :setup_config, roles: :app do
sudo "ln -nfs #{current_path}/config/nginx.conf /etc/nginx/sites-enabled/#{application}"
sudo "ln -nfs #{current_path}/config/unicorn_init.sh /etc/init.d/unicorn_#{application}"
run "mkdir -p #{shared_path}/config"
put File.read("config/database.example.yml"), "#{shared_path}/config/database.yml"
put File.read("config/initializers/secret_token.example.rb"), "#{shared_path}/config/secret_token.rb"
puts "Now edit the config files in #{shared_path}."
end
after "deploy:setup", "deploy:setup_config"
task :symlink_config, roles: :app do
run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
run "ln -nfs #{shared_path}/config/secret_token.rb #{release_path}/config/initializers/secret_token.rb"
end
after "deploy:finalize_update", "deploy:symlink_config"
desc "Make sure local git is in sync with remote."
task :check_revision, roles: :web do
unless `git rev-parse HEAD` == `git rev-parse origin/master`
puts "WARNING: HEAD is not the same as origin/master"
puts "Run `git push` to sync changes."
exit
end
end
before "deploy", "deploy:check_revision"
end
Capfile
load 'deploy'
load 'deploy/assets'
load 'config/deploy'
Shake hands with github
# follow the steps in this guide if receive permission denied(public key)
# https://help.github.com/articles/error-permission-denied-publickey
ssh [email protected]
Add ssh key to digitalocean
cat ~/.ssh/id_rsa.pub | ssh -p 1026 [email protected] 'cat >> ~/.ssh/authorized_keys'
Create repo and push to github
# Add config/database.yml to .gitignore
cp config/database.yml config/database.example.yml
git init
git add .
git commit -m "Inital Commit"
git remote add origin [email protected]:username/reponame
git push origin master
deployment
cap deploy:setup
edit shared configuration files on server
emacs /home/deploy/apps/projectname/shared/config/database.yml emacs /home/deploy/apps/projectname/shared/config/initializers/secret_token.rb
then finish deploying
cap deploy:cold
after deploy:cold
sudo rm /etc/nginx/sites-enabled/default
sudo service nginx restart
sudo update-rc.d -f unicorn_projectname defaults
Make changes and deploy
# Make changes
git add .
git commit -m "Changes"
git push origin master
cap deploy
Resources from Railscasts/digital ocean documentation. For use if puppet or chef is a little over your head. I know you can spawn up a rails app using nginx and unicorn with mysql, but you don't learn much that way!
Hopefully I didn't miss any steps, although I'm sure I did. Please leave comments if you run into troubles.
In the DNS section of the admin interface, click (Add Domain) and pick your droplet. Then type in the domain name you want to set (e.g. devleverage.com)
This will automatically create an A record for @ and setup the Name Server entries.
Add an A record for www with the VPS IP address Add an A record for mail with the VPS IP address
Add a CNAME to the DNS (with name = smtp and hostname = @)
Add an MX record with mail.. and the priority 10
for example, mail.devleverage.com. and 10 NOTE: the name has to end with a period
A PTR record is automatically created that resolves your IP back to the name of your droplet. You don't need to do anything.
Add a TXT record with (generated by Microsoft http://www.microsoft.com/mscorp/safety/content/technologies/senderid/wizard/)
v=spf1 mx ptr ip4:192.241.231.94 mx:mail.devleverage.com ~all
or (this may be enough)
v=spf1 ip4:192.241.231.94 ~all
sudo apt-get install mailutils
https://www.digitalocean.com/community/articles/how-to-install-and-setup-postfix-on-ubuntu-12-04
sudo apt-get install postfix
not sure if you need to to a reconfigure to set all the options
sudo dpkg-reconfigure postfix
During the installation, you will see a dialogue box appear, asking you which kind of installation you would prefer. Select “Internet Site”.
Follow up by entering the name of your domain.
Once Postfix is installed there are a few steps that need to be taken before it is fully functional.
Once Postfix is installed, go ahead and open the main configuration file.
sudo nano /etc/postfix/main.cf
There are a few changes that should be made in this file.
myhostname = example.com
home_mailbox = Maildir/
Put in name of your domain into myhostname.
If you want to have mail forwarded to other domains, replace alias_maps with virtual_alias_maps and point it to /etc/postfix/virtual.
virtual_alias_maps = hash:/etc/postfix/virtual
To just use simple aliases, add anything else you want to /etc/aliases. For example, to have emails sent to root be redirected to you (e.g. [email protected] ==> [email protected]) add the following line to /etc/aliases
root: you
contact: you
once you've added all your aliases,
newaliases
The rest of the entries are described below
mydestination defines the domains that postfix is going to serve, in this case—localhost and your domain (eg. example.com).
relayhost can be left, as is the default, empty.
mynetworks defines who can use the mail server. This should be set to local—creating an open mail server is asking for SPAM. This will usually have damaging effects on your server and may put you in line for discipline from your web hosting provider.
If it is not set up by default, as it should be, make sure you have the following text on that line:
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
in the main.cf file, add the following smtpd_sasl_type = dovecot
Debian/Ubuntu users: Postfix is setup by default to run chrooted, so it is best to leave it as-is below
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated,
reject_unauth_destination
in the main.cf file, add the following smtpd_sasl_type = dovecot
Debian/Ubuntu users: Postfix is setup by default to run chrooted, so it is best to leave it as-is below
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated,
reject_unauth_destination
The rest of the lines are set by default.
In the /etc/postfix/master.cf look and uncomment:
submission inet n - - - - smtpd -o syslog_name=postfix/submission -o smtpd_tls_security_level=encrypt -o smtpd_sasl_auth_enable=yes -o smtpd_client_restrictions=permit_sasl_authenticated,reject -o milter_macro_daemon_name=ORIGINATING
In the /etc/postfix/master.cf look and uncomment:
submission inet n - - - - smtpd -o syslog_name=postfix/submission -o smtpd_tls_security_level=encrypt -o smtpd_sasl_auth_enable=yes -o smtpd_client_restrictions=permit_sasl_authenticated,reject -o milter_macro_daemon_name=ORIGINATING
Save, exit, and reload the configuration file to put your changes into effect:
sudo /etc/init.d/postfix reload
#Install Dovecot
sudo apt-get install dovecot-imapd dovecot-pop3d
edit /etc/dovecot/dovecot.conf
protocols = pop3 pop3s imap imaps
mail_location = maildir:/home/%u/Maildir
setup imap protocol to listen for non-localhost connections
edit /etc/dovecot/conf.d/20-imap.conf
protocol imap { listen = *:143 ssl_listen = *:993 ... }
pre-create the Maildir for future users
sudo maildirmake.dovecot /etc/skel/Maildir sudo maildirmake.dovecot /etc/skel/Maildir/.Drafts sudo maildirmake.dovecot /etc/skel/Maildir/.Sent sudo maildirmake.dovecot /etc/skel/Maildir/.Trash sudo maildirmake.dovecot /etc/skel/Maildir/.Templates
and for any existing users
sudo cp -r /etc/skel/Maildir /home// sudo chown -R : /home//Maildir sudo chmod -R 700 /home//Maildir
and then restart dovcot
sudo service dovecot restart
To check that it is running, type the command
ps -A | grep dovecot
then telnet in
sudo apt-get install telnet
telnet localhost pop3
telnet localhost imap2
If you see something like the following, the installation has been successful.
matt@kalliope:~$ telnet localhost pop3
Trying localhost...
Connected to localhost.
Escape character is '^]'.
+OK dovecot ready.
edit /etc/dovecot/dovecot.conf
ssl = yes
ssl_cert_file = /etc/ssl/certs/ssl-cert-snakeoil.pem
ssl_key_file = /etc/ssl/private/ssl-cert-snakeoil.key
add a A Record to the DNS (with name = mail and hostname = your IP)
add an A Record to the DNS (with name = smtp and hostname = your IP)
Add the following to the bottom of dovecot.conf
auth default { mechanisms = plain login passdb pam { } userdb passwd { } socket listen { client { # Assuming the default Postfix $queue_directory setting path = /var/spool/postfix/private/auth mode = 0660 # Assuming the default Postfix user and group user = postfix group = postfix } # deliver and some other programs need also auth-master: #master { # path = /var/run/dovecot/auth-master # mode = 0600 #} } }