Skip to content

Instantly share code, notes, and snippets.

@dayvough
Last active April 14, 2017 11:06
Show Gist options
  • Save dayvough/ebc3a2fd7bb62cf02916827acf7c5738 to your computer and use it in GitHub Desktop.
Save dayvough/ebc3a2fd7bb62cf02916827acf7c5738 to your computer and use it in GitHub Desktop.
Fresh Server Setup

Vars

app_dir = /home/deploy/app_name

Users, permissions, and services

https://www.codelitt.com/blog/my-first-10-minutes-on-a-server-primer-for-securing-ubuntu/

RVM

gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
\curl -sSL https://get.rvm.io | bash -s stable
source ~/.profile
rvm requirements
rvm install 2.3.0
exit
ssh deploy@example.com
rvm --default use 2.3.0

Bundler

sudo echo "gem: --no-ri --nordoc" >> ~/.gemrc
gem install bundler

Miscellaneous packages

sudo apt-get install nodejs git-core nginx imagemagick libpq-dev libv8-dev libcurl3-dev postgresql

PostgreSQL

sudo -u postgres psql postgres
CREATE USER app_name WITH CREATEDB PASSWORD 'app_password';
CREATE DATABASE app_name_production OWNER app_name;
sudo nano /etc/postgresql/9.5/main/pg_hba.conf

# replace 'peer' with 'md5' in local
------------------------------------------------------------------
# Database administrative login by Unix domain socket
local   all             postgres                                peer

# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
local   all             all                                     md5
# IPv4 local connections:
host    all             all             127.0.0.1/32            md5
# IPv6 local connections:
host    all             all             ::1/128                 md5
------------------------------------------------------------------
sudo /etc/init.d/postgresql restart

Nginx

cd /etc/nginx/sites-enabled
sudo rm -rf default
sudo nano app_name
https://gist.github.com/dayvough/b6e75be8603f71a7cfe54453be71b202

Config

sudo mkdir -pv /home/deploy/app_name/shared/config
sudo chown -R deploy:deploy /home/deploy
sudo nano /home/deploy/app_name/shared/config/database.yml
default: &default
  adapter: postgresql
  username: app_name
  password: app_password
  host: localhost

staging:
  <<: *default
  database: app_name_staging
  
production:
  <<: *default
  database: app_name_production
sudo nano /home/deploy/app_name/shared/config/secrets.yml

Unicorn

# [Local] app-name/config/unicorn.rb

worker_processes 4
user 'deploy', 'deploy'

APP_DEPLOY_DIR = "/home/deploy/app_name"
working_directory APP_DEPLOY_DIR + "/current"
 
listen "#{APP_DEPLOY_DIR}/shared/pids/unicorn.sock", :backlog => 64
listen 8000, :tcp_nopush => true

timeout 180

pid "#{APP_DEPLOY_DIR}/shared/pids/unicorn.pid"

stderr_path "#{APP_DEPLOY_DIR}/shared/log/unicorn.stderr.log"
stdout_path "#{APP_DEPLOY_DIR}/shared/log/unicorn.stdout.log"

preload_app true
GC.respond_to?(:copy_on_write_friendly=) and
 GC.copy_on_write_friendly = true

before_exec do |server|
 ENV['BUNDLE_GEMFILE'] = "#{APP_DEPLOY_DIR}/current/Gemfile"
end

before_fork do |server, worker|
 defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
end
 
after_fork do |server, worker| 
 defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

Gems

group :development do
  gem 'guard'
  gem 'guard-rspec', '~> 4.6', require: false
  gem 'foreman'
  gem 'pry'
  gem 'capistrano-rails', '~> 1.1', require: false
  gem 'capistrano-bundler', '~> 1.1', require: false
  gem 'capistrano-secrets-yml', '~> 1.0.0'
  gem 'rvm1-capistrano3', require: false
  gem 'capistrano3-unicorn'
  # gem 'slackistrano'
end

group :test do
  gem 'rspec_junit_formatter', '0.2.2'
  gem 'database_cleaner'
  gem 'shoulda-matchers', '~> 3.1'
end

group :development, :test do
  gem 'byebug'
  gem 'rspec', '~> 3.5.0.beta1'
  gem 'rspec-core', '~> 3.5.0.beta1'
  gem 'rspec-rails', '~> 3.5.0.beta1'
  gem 'rails-controller-testing'
  gem 'factory_girl_rails'
end

group :production do
  gem 'unicorn'
end

Add Ruby version

# [LOCAL]
echo "2.3.0" >> .ruby-version

Install Capistrano

# [LOCAL]
cap install
nano config/deploy/production.rb
role :app, 'deploy@123.456.789.123'
role :web, 'deploy@123.456.789.123'
role :db,  'deploy@123.456.789.123'
set :rails_env, :production

Capistrano

# [Local] app-name/Capfile
require "capistrano/setup"
require "capistrano/deploy"

require 'rvm1/capistrano3'
require 'capistrano/bundler'
require 'capistrano/secrets_yml'
require 'capistrano3/unicorn'
require "capistrano/rails/assets"
require 'capistrano/rails/migrations'

Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }

def relative_path(from_str, to_str)
 require 'pathname'
 Pathname.new(to_str).relative_path_from(Pathname.new(from_str)).to_s
end
 
Rake::Task["deploy:symlink:linked_dirs"].clear
# [Local] app-name/config/deploy.rb

# Lock at current Capistrano version
lock '3.5.0'

set :stages, %w(production staging)
set :default_stage, "staging"

set :application, 'app_name'
set :repo_url, 'git@github.com:user/app-name.git'

set :branch, "master"
set :user, "deploy"
set :ssh_options, { forward_agent: true }
set :deploy_to, "/home/deploy/#{fetch(:application)}"
set :unicorn_config_path, File.join(fetch(:deploy_to), "current", "config", "unicorn.rb")
set :unicorn_pid, File.join(fetch(:deploy_to), "shared", "pids", "unicorn.pid")
set :pty, true
set :keep_releases, 5

set :linked_files, %w{config/database.yml config/secrets.yml}
set :linked_dirs, %w{bin log tmp pids vendor/bundle public/system}

after 'deploy:publishing', 'deploy:restart'

namespace :deploy do
  desc 'Restart application'
  task :restart do
    on roles(:app), in: :sequence, wait: 5 do
      # Execute restarting
    end
  end

  after :publishing, :restart

  after :restart, :clear_cache do
    on roles(:web), in: :groups, limit: 3, wait: 10 do
      # Here we can do anything such as:
      # within release_path do
      #   execute :rake, 'cache:clear'
      # end
    end
  end

  task :restart do
    invoke 'unicorn:legacy_restart'
  end

end
ssh-add ~/.ssh/id_rsa.pub
cap production deploy

Setup

  1. Add app-name/shared/config/secrets.yml

Finished!

TODO

  1. certbot
@dayvough
Copy link
Author

  • Make app_name changes more visible
  • Capistrano installation missing
  • Whenever installation missing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment