Skip to content

Instantly share code, notes, and snippets.

@narath
Last active May 3, 2020 22:23
Show Gist options
  • Save narath/56b858aa8c5dedfdea9336e79511be04 to your computer and use it in GitHub Desktop.
Save narath/56b858aa8c5dedfdea9336e79511be04 to your computer and use it in GitHub Desktop.
Digital Ocean Rails Droplet deployment with Rails 6 and Capistrano. See https://dev.narath.io/2020/04/19/deploying-rails-6-using-capistrano-to-a-digital-ocean-rails-droplet.html for instructions.
require "capistrano/setup"
require "capistrano/deploy"
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git
require "capistrano/rails"
require "capistrano/bundler"
require "capistrano/rvm"
require "capistrano/puma"
# require "whenever/capistrano"
# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
# add to config/deploy.rb
namespace :deploy do
namespace :check do
before :linked_files, :copy_linked_files_if_needed do
on roles(:app), in: :sequence, wait: 10 do
%w{master.key database.yml}.each do |config_filename|
unless test("[ -f #{shared_path}/config/#{config_filename} ]")
upload! "config/#{config_filename}", "#{shared_path}/config/#{config_filename}"
end
end
end
end
end
end
# config valid for current version and patch releases of Capistrano
lock "~> 3.13.0"
# helpful resources
# https://www.bacancytechnology.com/blog/deploy-rails-application-with-capistrano
# https://thoughtbot.com/blog/github-with-capistrano
set :application, "app-name"
set :repo_url, "[email protected]:your-git-username/app-repo-name.git"
set :user, "rails"
# Default branch is :master
# ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp
set :repository_cache, "git_cache"
set :deploy_via, :remote_cache
set :ssh_options, { forward_agent: true }
set :deploy_to, "/home/#{fetch(:user)}/#{fetch(:application)}"
# Default value for :format is :airbrussh.
# set :format, :airbrussh
# You can configure the Airbrussh format using :format_options.
# These are the defaults.
# set :format_options, command_output: true, log_file: "log/capistrano.log", color: :auto, truncate: :auto
# Default value for :pty is false
# set :pty, true
# use symlinking of files
append :linked_dirs, 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', '.bundle', 'public/system', 'public/uploads'
append :linked_files, 'config/database.yml', 'config/master.key'
# Default value for default_env is {}
# set :default_env, { path: "/opt/ruby/bin:$PATH" }
# Default value for local_user is ENV['USER']
# set :local_user, -> { `git config user.name`.chomp }
# Default value for keep_releases is 5
# set :keep_releases, 5
# Defaults to nil (no asset cleanup is performed)
# If you use Rails 4+ and you'd like to clean up old assets after each deploy,
# set this to the number of versions to keep
set :keep_assets, 2
# Uncomment the following to require manually verifying the host key before first deploy.
# set :ssh_options, verify_host_key: :secure
# RAILS specific settings
# If the environment differs from the stage name
# set :rails_env, 'staging'
# Defaults to :db role
# App is recommended since the framework manages this
set :migration_role, :app
# Defaults to the primary :db server
set :migration_servers, -> { primary(fetch(:migration_role)) }
# Defaults to false
# Skip migration if files in db/migrate were not modified
set :conditionally_migrate, true
# Defaults to [:web]
set :assets_roles, [:web, :app]
# Defaults to 'assets'
# This should match config.assets.prefix in your rails config/application.rb
set :assets_prefix, 'prepackaged-assets'
# Defaults to ["/path/to/release_path/public/#{fetch(:assets_prefix)}/.sprockets-manifest*", "/path/to/release_path/public/#{fetch(:assets_prefix)}/manifest*.*"]
# This should match config.assets.manifest in your rails config/application.rb
set :assets_manifests, ['app/assets/config/manifest.js']
# RAILS_GROUPS env value for the assets:precompile task. Default to nil.
set :rails_assets_groups, :assets
# If you need to touch public/images, public/javascripts, and public/stylesheets on each deploy
set :normalize_asset_timestamps, %w{public/images public/javascripts public/stylesheets}
# upload my master.key
namespace :deploy do
namespace :check do
before :linked_files, :copy_linked_files_if_needed do
on roles(:app), in: :sequence, wait: 10 do
%w{master.key database.yml}.each do |config_filename|
unless test("[ -f #{shared_path}/config/#{config_filename} ]")
upload! "config/#{config_filename}", "#{shared_path}/config/#{config_filename}"
end
end
end
end
end
end
server 'your-server-name-or-ip', user: "rails", roles: %w{app db web}
# rails credentials:edit
secret_key_base: YOUR_SECRET_KEY
production:
db_user: rails
db_pass: YOUR_RAILS_DB_PASSWORD_FROM_THE_MESSAGE_OF_THE_DAY
db_name: your-app-name_production
db_host: localhost
default: &default
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
development:
<<: *default
database: app-name_development
test:
<<: *default
database: app-name_test
production:
<<: *default
database: <%= Rails.application.credentials.dig(:production, :db_name) %>
username: <%= Rails.application.credentials.dig(:production, :db_user) %>
password: <%= Rails.application.credentials.dig(:production, :db_pass) %>
host: <%= Rails.application.credentials.dig(:production, :db_host) %>
# add this to your Gemfile
group :development do
gem 'capistrano', '~> 3.13', require: false
gem 'capistrano-rails', '~> 1.4', require: false
gem 'capistrano-bundler', require: false
gem 'capistrano-rvm', require: false
gem 'capistrano-puma', require: false
end
namespace :deploy do
desc "Restart Rails Service"
task :restart do
on roles(:app) do
execute "sudo /bin/systemctl restart rails.service"
end
end
end
after "deploy:finishing", "deploy:restart"
# thanks to https://makandracards.com/makandra/52382-capistrano-task-to-tail-remote-application-logs-of-multiple-servers
namespace :logs do
desc 'Tail remote log files'
task :app do
on roles :app do
logfile = ENV['LOG'] || fetch(:rails_env)
execute %(tail -n0 -F #{shared_path}/log/#{logfile}.log | while read line; do echo "$(hostname): $line"; done)
end
end
desc 'Tail rails service'
task :service do
on roles :app do
execute %(/bin/journalctl -u rails.service -f)
end
end
end
server {
root /home/rails/hilo/current/public;
server_name hilo.deeply.care;
index index.htm index.html;
location ~ /.well-known {
allow all;
}
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
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;
}
# needed to allow serving of assets and other public files
location ~ ^/(assets|packs|graphs)/ {
gzip_static on;
expires 1y;
add_header Cache-Control public;
add_header Last-Modified "";
add_header ETag "";
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/hilo.deeply.care/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/hilo.deeply.care/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = hilo.deeply.care) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name hilo.deeply.care;
return 404; # managed by Certbot
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment