Skip to content

Instantly share code, notes, and snippets.

@ricardodovalle
Forked from alekpopovic/1 setup vps
Created September 26, 2017 00:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ricardodovalle/dbf5c7b6fed25c1a4093d0abdf060601 to your computer and use it in GitHub Desktop.
Save ricardodovalle/dbf5c7b6fed25c1a4093d0abdf060601 to your computer and use it in GitHub Desktop.
Deploy Rails 5.1.1 to VPS(Ubuntu 16.04.2 LTS). Nginx mainline + pagespeed, Puma with Jungle, Capistrano3, PostgreSQL 9.6, RVM, Certbot
root# apt-get update
root# apt-get upgrade
// dependencies for Ruby
root# apt-get install -y git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev \
libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev python-software-properties libffi-dev \
libpcre3-dev unzip
// Node.js v7
root# curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash -
root# apt-get install -y nodejs
// Yarn
root# curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
root# echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
root# sudo apt-get update && sudo apt-get install yarn
// Postgresql 9.6
root# echo 'deb http://apt.postgresql.org/pub/repos/apt/ xenial-pgdg main' > /etc/apt/sources.list.d/pgdg.list
root# wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
root# apt-get update && apt-get install -y postgresql-9.6 libpq-dev
// fix perl: warning: Setting locale failed.
root# echo -e 'LANG="en_US.UTF-8"\nLC_ALL="en_US.UTF-8"\nLANGUAGE="en_US:en"' > /etc/default/locale
// mainline nginx with stable ngx_pagespeed
root# bash <(curl -f -L -sS https://ngxpagespeed.com/install) -y --nginx-version latest -a ' \
--prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx \
--group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module \
--with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module \
--with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module \
--with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module \
--with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module \
--with-stream_ssl_module --with-stream_ssl_preread_module'
root# adduser --system --no-create-home --shell /bin/false --group --disabled-login nginx
root# wget -O /etc/nginx/nginx.conf https://gist.githubusercontent.com/PavelBezpalov/6525017b7ab61c843264a0b544acfdd6/raw/nginx.conf
root# mkdir /etc/nginx/sites-enabled
root# mkdir /etc/nginx/sites-available
root# mkdir /var/cache/nginx
root# mkdir -p /var/ngx_pagespeed_cache
root# chown nginx:nginx /var/ngx_pagespeed_cache
root# wget -O /etc/init.d/nginx https://gist.githubusercontent.com/PavelBezpalov/6525017b7ab61c843264a0b544acfdd6/raw/nginx
root# chmod +x /etc/init.d/nginx
root# systemctl enable nginx.service
// certbot
root# apt-get install software-properties-common
root# add-apt-repository ppa:certbot/certbot
root# apt-get update
root# apt-get install certbot
// deployer user in sudo group
root# adduser deployer
root# gpasswd -a deployer sudo
// disable ssh root login, permit password login
root# nano /etc/ssh/sshd_config
EDIT:
PermitRootLogin no
PasswordAuthentication yes
SAVE:
ctrl + x
y
enter
root# service ssh restart
root# exit
ssh deployer@server
// rvm, ruby 2.4.1, bundler
deployer$ sudo apt-get install libgdbm-dev libncurses5-dev automake libtool bison libffi-dev
deployer$ gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
deployer$ curl -sSL https://get.rvm.io | bash -s stable
deployer$ echo "gem: --no-document" > ~/.gemrc
deployer$ source ~/.rvm/scripts/rvm
deployer$ rvm install 2.4.1 && rvm use 2.4.1 --default
deployer$ gem install bundler
// postgresql deployer user, project db
deployer$ sudo su - postgres
deployer$ createuser --pwprompt deployer
deployer$ createdb -O deployer <<APP_DB_NAME>>
deployer$ exit
ADD TO Gemfile:
group :development do
gem 'capistrano', '~> 3.8', '>= 3.8.1'
gem 'capistrano-rvm', '~> 0.1.2'
gem 'capistrano-rails', '~> 1.2', '>= 1.2.3'
gem 'capistrano3-puma', git: 'https://github.com/seuros/capistrano-puma.git', ref: '00708fa'
gem 'capistrano-nginx', '~> 1.0'
gem 'capistrano-upload-config', '~> 0.7.0'
gem 'sshkit-sudo', '~> 0.1.0'
end
RUN:
your_app$ bundle install
your_app$ cap install
EDIT Capfile AS ATTACHED Capfile
EDIT config/deploy.rb AS ATTACHED deploy.rb AND CHANGE VARIABLES IN IT
RUN:
your_app$ cp config/database.yml config/database.yml.example
your_app$ cp config/secrets.yml config/secrets.yml.example
your_app$ cap production config:init
your_app$ echo '/config/database.production.yml' >> .gitignore
your_app$ echo '/config/secrets.production.yml' >> .gitignore
EDIT WITH YOUR PARAMETERS:
/config/database.production.yml
/config/secrets.production.yml
RUN:
your_app$ rails g capistrano:nginx_puma:config
EDIT OR LEAVE AS IS:
config/deploy/templates/nginx_conf.erb
config/deploy/templates/puma.rb.erb
ADD RUBY-VERSION FILE FOR PUMA JUNGLE:
your_app$ echo 'ruby-2.4.1' > .ruby-version
GIT COMMIT AND PUSH CHANGES
RUN:
your_app$ cap production deploy
CONGRATULATION! ALL DONE!
CHECK YOUR RUNNIG SERVER!
Using ENV variables:
store variables in /etc/environment like:
export VAR_NAME=value
require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/scm/git'
install_plugin Capistrano::SCM::Git
require 'capistrano/rvm'
require 'capistrano/rails'
require 'capistrano/puma'
install_plugin Capistrano::Puma
install_plugin Capistrano::Puma::Nginx
install_plugin Capistrano::Puma::Jungle
require 'capistrano/nginx'
require 'capistrano/upload-config'
require 'sshkit/sudo'
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
# config valid only for current version of Capistrano
lock '3.8.1'
set :application, '<<YOUR APPNAME>>'
set :repo_url, '<<YOUR APP REPO>>'
# ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp
set :user, 'deployer'
server '<<YOUR SERVER>>', user: "#{fetch(:user)}", roles: %w{app db web}, primary: true
set :deploy_to, "/home/#{fetch(:user)}/apps/#{fetch(:application)}"
set :pty, true
set :rvm_ruby_version, '2.4.1'
append :linked_files, 'config/database.yml', 'config/secrets.yml', 'config/puma.rb'
append :linked_dirs, 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system', 'public/uploads'
set :config_example_suffix, '.example'
set :config_files, %w{config/database.yml config/secrets.yml}
set :puma_conf, "#{shared_path}/config/puma.rb"
namespace :deploy do
before 'check:linked_files', 'config:push'
before 'check:linked_files', 'puma:jungle:setup'
before 'check:linked_files', 'puma:nginx_config'
after 'puma:smart_restart', 'nginx:restart'
end
#!/bin/sh
### BEGIN INIT INFO
# Provides: nginx
# Required-Start: $network $remote_fs $local_fs
# Required-Stop: $network $remote_fs $local_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Stop/start nginx
### END INIT INFO
# Author: Sergey Budnevitch <sb@nginx.com>
PATH=/sbin:/usr/sbin:/bin:/usr/bin
if [ -L $0 ]; then
SCRIPTNAME=`/bin/readlink -f $0`
else
SCRIPTNAME=$0
fi
sysconfig=`/usr/bin/basename $SCRIPTNAME`
[ -r /etc/default/$sysconfig ] && . /etc/default/$sysconfig
DESC=${DESC:-nginx}
NAME=${NAME:-nginx}
CONFFILE=${CONFFILE:-/etc/nginx/nginx.conf}
DAEMON=${DAEMON:-/usr/sbin/nginx}
PIDFILE=${PIDFILE:-/var/run/nginx.pid}
SLEEPSEC=${SLEEPSEC:-1}
UPGRADEWAITLOOPS=${UPGRADEWAITLOOPS:-5}
CHECKSLEEP=${CHECKSLEEP:-3}
[ -x $DAEMON ] || exit 0
DAEMON_ARGS="-c $CONFFILE $DAEMON_ARGS"
. /lib/init/vars.sh
. /lib/lsb/init-functions
do_start()
{
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
$DAEMON_ARGS
RETVAL="$?"
return "$RETVAL"
}
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --oknodo --retry=TERM/30/KILL/5 --pidfile $PIDFILE
RETVAL="$?"
rm -f $PIDFILE
return "$RETVAL"
}
do_reload() {
#
start-stop-daemon --stop --signal HUP --quiet --pidfile $PIDFILE
RETVAL="$?"
return "$RETVAL"
}
do_configtest() {
if [ "$#" -ne 0 ]; then
case "$1" in
-q)
FLAG=$1
;;
*)
;;
esac
shift
fi
$DAEMON -t $FLAG -c $CONFFILE
RETVAL="$?"
return $RETVAL
}
do_upgrade() {
OLDBINPIDFILE=$PIDFILE.oldbin
do_configtest -q || return 6
start-stop-daemon --stop --signal USR2 --quiet --pidfile $PIDFILE
RETVAL="$?"
for i in `/usr/bin/seq $UPGRADEWAITLOOPS`; do
sleep $SLEEPSEC
if [ -f $OLDBINPIDFILE -a -f $PIDFILE ]; then
start-stop-daemon --stop --signal QUIT --quiet --pidfile $OLDBINPIDFILE
RETVAL="$?"
return
fi
done
echo $"Upgrade failed!"
RETVAL=1
return $RETVAL
}
do_checkreload() {
templog=`/bin/mktemp --tmpdir nginx-check-reload-XXXXXX.log`
trap '/bin/rm -f $templog' 0
/usr/bin/tail --pid=$$ -n 0 --follow=name /var/log/nginx/error.log > $templog &
/bin/sleep 1
start-stop-daemon --stop --signal HUP --quiet --pidfile $PIDFILE
/bin/sleep $CHECKSLEEP
/bin/grep -E "\[emerg\]|\[alert\]" $templog
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc -p "$PIDFILE" "$DAEMON" "$NAME" && exit 0 || exit $?
;;
configtest)
do_configtest
;;
upgrade)
do_upgrade
;;
reload|force-reload)
log_daemon_msg "Reloading $DESC" "$NAME"
do_reload
log_end_msg $?
;;
restart|force-reload)
log_daemon_msg "Restarting $DESC" "$NAME"
do_configtest -q || exit $RETVAL
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
check-reload)
do_checkreload
RETVAL=0
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|status|restart|reload|force-reload|upgrade|configtest|check-reload}" >&2
exit 3
;;
esac
exit $RETVAL
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
ssl_ecdh_curve prime256v1:secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off; # Requires nginx >= 1.5.9
ssl_stapling on; # Requires nginx >= 1.3.7
ssl_stapling_verify on; # Requires nginx => 1.3.7
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY; # change to SAMEORIGIN for iframes
add_header X-Content-Type-Options nosniff;
gzip on;
gzip_vary on;
gzip_types application/ecmascript;
gzip_types application/javascript;
gzip_types application/json;
gzip_types application/pdf;
gzip_types application/postscript;
gzip_types application/x-javascript;
gzip_types image/svg+xml;
gzip_types text/css;
gzip_types text/csv;
gzip_types text/javascript;
gzip_types text/plain;
gzip_types text/xml;
gzip_http_version 1.0;
pagespeed on;
pagespeed FetchWithGzip on;
# Needs to exist and be writable by nginx. Use tmpfs for best performance.
pagespeed FileCachePath /var/ngx_pagespeed_cache;
pagespeed ModPagespeedCreateSharedMemoryMetadataCache "/var/ngx_pagespeed_cache" 51200;
pagespeed ModPagespeedFileCacheSizeKb 1024000;
pagespeed LRUCacheKbPerProcess 8192;
pagespeed LRUCacheByteLimit 16384;
#pagespeed Disallow "*.svg*";
include /etc/nginx/sites-enabled/*;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment