Skip to content

Instantly share code, notes, and snippets.

@plombix

plombix/nginx.md

Last active Sep 5, 2016
Embed
What would you like to do?

Update and upgrade the system

sudo apt-get update && sudo apt-get upgrade && sudo apt-get dist-upgrade && sudo apt-get autoremove
sudo reboot

Configure timezone

sudo dpkg-reconfigure tzdata
sudo apt-get install -y ntp
sudo ntpdate ntp.ubuntu.com
date

Create new user

sudo adduser ubuntu
sudo adduser ubuntu sudo

Edit /etc/sudoers

%sudo ALL=(ALL:ALL) ALL
ubuntu ALL=NOPASSWD: ALL

Environment variables

Edit /etc/profile

export PATH=/opt/nginx/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
export RAILS_ENV=production
export LC_ALL=en_US.UTF-8

Edit /etc/environment

PATH=/opt/nginx/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
RAILS_ENV=production
LC_ALL=en_US.UTF-8

Edit /etc/sudoers

Defaults secure_path="/opt/nginx/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

Some libraries for Mysql, ImageMagick, Node, etc

sudo apt-get install -y libmagickwand-dev libmysqlclient15-dev nodejs npm imagemagick libpq-dev htop curl

Ruby

sudo apt-get install -y libyaml-dev libssl-dev libreadline-dev libxml2-dev libxslt1-dev libffi-dev build-essential

Compiled:

wget http://cache.ruby-lang.org/pub/ruby/2.1/ruby-2.1.4.tar.gz
tar xvfz ruby-2.1.4.tar.gz
cd ruby-2.1.4/
./configure --prefix=/opt/ruby --disable-install-rdoc
make
sudo make install
sudo gem install bundler

Package:

wget -q -O - http://apt.hellobits.com/hellobits.key | sudo apt-key add -
echo 'deb [arch=amd64] http://apt.hellobits.com/ trusty main' | sudo tee /etc/apt/sources.list.d/hellobits.list
sudo apt-get update
sudo apt-get install -y ruby-2.3
sudo gem install bundler

GIT

sudo apt-get install -y git

OpenSSL

cd /opt
sudo wget http://www.openssl.org/source/openssl-1.0.2g.tar.gz
sudo tar xvfz openssl-1.0.2g.tar.gz
sudo mv openssl-1.0.2g openssl
cd openssl/
sudo ./config
sudo make
sudo make install

Nginx

wget http://nginx.org/download/nginx-1.9.9.tar.gz
tar xvfz nginx-1.9.9.tar.gz
cd nginx-1.9.9/
./configure --prefix=/opt/nginx --with-http_ssl_module --with-openssl=/opt/openssl
sudo make
sudo make install

Nginx settings

cd /opt/nginx/conf
sudo rm nginx.conf
and replace by:
 worker_processes    1;

  error_log   /var/log/nginx/error.log;
  pid         /var/run/nginx.pid;

  events {
    worker_connections  1024;
  }

  http {
    include             mime.types;
    default_type        application/octet-stream;
    access_log          /var/log/nginx/access.log;
    sendfile            on;
    keepalive_timeout   65;
    gzip                on;

    client_max_body_size 4M;
    client_body_buffer_size 128k;

    # Based on https://gist.github.com/plentz/6737338
    server_tokens off;
    add_header Access-Control-Allow-Origin '*';
    add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://ssl.google-analytics.com https://assets.zendesk.com https://connect.facebo    ok.net; img-src 'self' https://ssl.google-analytics.com https://s-static.ak.facebook.com https://assets.zendesk.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://ass    ets.zendesk.com; font-src 'self' https://themes.googleusercontent.com; frame-src https://assets.zendesk.com https://www.facebook.com https://s-static.ak.facebook.com https://tautt.zendesk.co    m; object-src 'none'";

    include /opt/nginx/conf/sites-enabled/*;
  }


sudo mkdir /var/log/nginx

sudo mkdir sites-enabled
cd sites-enabled
create:
upstream project {
    server unix:///var/tmp/project.sock;
}

server {
    listen		80;
    server_name localhost;
    
    root /var/www/project/current/public;
    
    if (-f /var/www/project/current/public/system/maintenance.html) {
        return 503;
    }
        
    error_page 503 @maintenance;
    location @maintenance {
        rewrite  ^(.*)$  /system/maintenance.html last;
        break;
    }

    location / {
        if (!-f $request_filename) {
            proxy_pass http://project;
        }
        
        proxy_redirect     off;

        proxy_set_header   Host             $host:$proxy_port;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

        client_max_body_size       10m;
        client_body_buffer_size    128k;

        proxy_connect_timeout      90;
        proxy_send_timeout         90;
        proxy_read_timeout         90;

        proxy_buffer_size          4k;
        proxy_buffers              4 32k;
        proxy_busy_buffers_size    64k;
        proxy_temp_file_write_size 64k;
    }
}

Or with SSL support

upstream project {
    server unix:///var/tmp/project.sock;
}

server {
    listen 80 default_server;
    server_name project.com;
    return 301 https://$server_name$request_uri;
}

# Based on https://gist.github.com/plentz/6737338
server {
    listen 443;
    server_name project.com;
    ssl on;

    ssl_certificate /path/of/my/cert/project.crt;
    ssl_certificate_key /path/of/my/cert/project.key;

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_prefer_server_ciphers on;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS';
    resolver 8.8.8.8;
    ssl_stapling on;
    ssl_trusted_certificate /path/of/my/cert/project.crt;

    location / {
        root /var/www/project/current/public;

        if (!-f $request_filename) {
            proxy_pass http://project;
            break;
        }
    }
}

Upstart script

cd /etc/init
create :
#nginx.conf
description "nginx webserver"

start on startup
stop on shutdown

respawn
expect fork
exec /opt/nginx/sbin/nginx

Now, you can run:

sudo (start|restart|stop) nginx

Deploy

Add user

sudo adduser deploy

SSH keys

sudo -iu deploy
ssh-keygen -t rsa

Add authorized keys

cd
vim .ssh/authorized_keys

Copy and paste public keys
exit

Create folder to deploy the app

sudo mkdir /var/www
sudo chown deploy:deploy -c -R /var/www

Capistrano

Capfile

require 'bundler/capistrano'
load 'deploy'
load 'deploy/assets'
load 'config/deploy' # remove this line to skip loading any of the default tasks

deploy.rb

set :repository,  "git@bitbucket.org:repo/repo.git"
set :user, "deploy"
set :use_sudo, false
set :scm, :git
set :keep_releases, 5
set :domain, "000.000.000.000"
set :application, "my_app"
set :rails_env, "production"
set :branch, "master"
set :deploy_to, "/var/www/#{application}"
set :port, 22
server domain, :app, :web, :db, :primary => true

namespace :deploy do
  task :start do ; end
  task :stop do ; end
  task :restart, :roles => :app, :except => { :no_release => true } do
    run "touch #{shared_path}/#{application}-restart.txt"
  end

  desc "Reload the database with seed data"
  task :seed do
    run "cd #{current_path}; bundle exec rake db:seed RAILS_ENV=#{rails_env}"
  end

  namespace :web do
    desc "Present a maintenance page to visitors"
    task :disable, :roles => :web, :except => { :no_release => true } do
      on_rollback { run "rm #{shared_path}/system/maintenance.html" }

      template = File.read("./public/503.html")

      put template, "#{shared_path}/system/maintenance.html", :mode => 0644
    end
  end

  namespace :assets do
    desc 'Install asset dependencies'
    task :install, roles: :app do
      run "cd #{latest_release} && bower install --no-color"
    end
  end
end

namespace :log do
  namespace :tail do
    desc "Show the production log"
    task :app, roles: :app do
      run "tail -f #{shared_path}/log/production.log" do |channel, stream, data|
        puts "#{data}"
        break if stream == :err
      end
    end
  end
end

namespace :db do
  desc "Create database yaml in shared path"
  task :configure do
    set :database do
      Capistrano::CLI.password_prompt "Database: "
    end

    set :database_username do
      Capistrano::CLI.password_prompt "Database Username: "
    end

    set :database_password do
      Capistrano::CLI.password_prompt "Database Password: "
    end

    set :database_host do
      Capistrano::CLI.password_prompt "Database Host: "
    end

    db_config = <<-EOF
      production:
        database: #{database}
        adapter: mysql2
        encoding: utf8
        reconnect: false
        pool: 5
        username: #{database_username}
        password: #{database_password}
        host: #{database_host}
    EOF

    run "mkdir -p #{shared_path}/config"
    put db_config, "#{shared_path}/config/database.yml"
  end

  desc "Make symlink for database yaml"
  task :symlink do
    run "ln -nfs #{shared_path}/config/database.yml #{latest_release}/config/database.yml"
  end
end

before 'deploy:assets:precompile',  'db:symlink'
before 'deploy:assets:precompile',  'deploy:assets:install'
before 'deploy:setup',              'db:configure'

Puma Upstart script

For each project, you must create the puma upstart file

cd /etc/init
create:
#project.conf
description "project server config"

pre-start script
  mkdir -p /var/log/puma
  chown deploy. /var/log/puma

  mkdir -p /var/run/puma
  chown deploy. /var/run/puma
end script

start on runlevel [23]
stop on shutdown

respawn

script
exec /bin/bash <<'EOT'
  # export RAILS_ENV=production
  # export APP_HOST=http://
  # Some environment variables...
  
  exec sudo -E -u deploy sh -c "cd /var/www/project/current && RAILS_ENV=production bundle exec puma -C config/puma.rb"
EOT
end script

With the upstart for each project, you can run:

sudo (start|restart|stop) project

Puma config

cd my/project/path/config
create:

puma.rb:

#!/usr/bin/env puma

threads 0, 4
# workers 3

bind  "unix:///var/tmp/project.sock"
pidfile "/var/run/puma/project.pid"
environment "production"
stdout_redirect "/var/log/puma/project.log"

Monit

sudo apt-get install -y monit

For each project, you must create the monit confg file

cd /etc/monit/conf.d
#project.conf
check file project-restart.txt with path /var/www/project/shared/project-restart.txt
   if changed timestamp
      then exec "/sbin/restart project"

Edit /etc/monit/monitrc

set daemon 60

Restart monit

sudo /etc/init.d/monit restart

Bower

sudo ln -s /usr/bin/nodejs /usr/bin/node
sudo npm install -g bower
@plombix

This comment has been minimized.

Copy link
Owner Author

@plombix plombix commented Sep 5, 2016

sorry for long post here is a potato:
[____]

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