Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save tsipiniuk/deb4b53a3195a3de550465b52dba71e8 to your computer and use it in GitHub Desktop.

Select an option

Save tsipiniuk/deb4b53a3195a3de550465b52dba71e8 to your computer and use it in GitHub Desktop.

Revisions

  1. @aquaflamingo aquaflamingo revised this gist Aug 26, 2018. 5 changed files with 4 additions and 4 deletions.
    Original file line number Diff line number Diff line change
    @@ -296,14 +296,14 @@ If test fails allow firewall to port 3000 temporarily[1](https://www.digitalocea

    Add `gem 'unicorn'` to `Gemfile` and `bundle`.

    Edit `config/unicorn.rb` paste [**Appendix B: config/unicorn.rb**](B-config-unicorn.md)
    Edit `config/unicorn.rb` paste [**Appendix B: config/unicorn.rb**](config-unicorn.md)

    Save and add logging to Rails App:
    ```
    $ mkdir -p shared/pids shared/sockets shared/log
    ```

    Edit and add unicorn init script from [**Appendix C: Unicorn Init Script**:](C-UNICORN-INIT.md)
    Edit and add unicorn init script from [**Appendix C: Unicorn Init Script**:](UNICORN-INIT.md)
    ```
    $ sudo nano /etc/init.d/unicorn_APPNAME
    ```
    @@ -336,7 +336,7 @@ If run fails and `systemctl` reveals little, ensure that you `rbenv`'s installat
    $ sudo apt-get install nginx
    ```

    Add NGINX reverse proxy config with block in [**Appendix D: NGINX Reverse Proxy**](D-NGINX-REV-PROXY.md)
    Add NGINX reverse proxy config with block in [**Appendix D: NGINX Reverse Proxy**](NGINX-REV-PROXY.md)

    ```
    $ sudo vi /etc/nginx/sites-available/default
    @@ -353,7 +353,7 @@ Restart NGINX
    ----
    ## 🙀 8. Complete

    Make sure you have all passwords: [**Appendix A: Inside Password Manager**](A-INSIDE-PW-MANAGER.md)
    Make sure you have all passwords: [**Appendix A: Inside Password Manager**](INSIDE-PW-MANAGER.md)

    All System Operational.

    File renamed without changes.
    File renamed without changes.
    File renamed without changes.
    File renamed without changes.
  2. @aquaflamingo aquaflamingo revised this gist Aug 17, 2018. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion !-Ubuntu-16-Nginx-Unicorn-Rails-DO.md
    Original file line number Diff line number Diff line change
    @@ -100,6 +100,8 @@ Test Login: `ssh deploy@server_ip`
    # Enter: y
    $ sudo ufw status
    # Status: active
    $ sudo ufw allow 80/tcp
    $ sudo ufw allow 443/tcp
    ```
    ----
    ## 💎 3. Install Ruby on Rails & rbenv [[Guide]](https://www.digitalocean.com/community/tutorials/how-to-install-ruby-on-rails-with-rbenv-on-ubuntu-16-04)
    @@ -290,7 +292,7 @@ If test fails allow firewall to port 3000 temporarily[1](https://www.digitalocea
    ```

    ----
    ## 🦄 6. Installing Unicorn [[Guide]](https://www.digitalocean.com/community/tutorials/how-to-deploy-a-rails-app-with-unicorn-and-nginx-on-ubuntu-14-04#configure-unicorn)
    ## 🦄 6. Installing Unicorn [[Guide]](https://www.digitalocean.com/community/tutorials/how-to-deploy-a-rails-app-with-unicorn-and-nginx-on-ubuntu-14-04#configure-unicorn) OR [[Passenger Phusion Guide]](https://www.phusionpassenger.com/library/walkthroughs/deploy/ruby/digital_ocean/nginx/oss/xenial/deploy_app.html)

    Add `gem 'unicorn'` to `Gemfile` and `bundle`.

  3. @aquaflamingo aquaflamingo renamed this gist Aug 15, 2018. 1 changed file with 0 additions and 0 deletions.
  4. @aquaflamingo aquaflamingo revised this gist Aug 15, 2018. 4 changed files with 132 additions and 0 deletions.
    16 changes: 16 additions & 0 deletions A-INSIDE-PW-MANAGER.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    ```
    Digital_Ocean:
    root_pass:
    deploy_pass:
    Postgres:
    appname:
    appname_password:
    Rails_Credentials
    RAILS_MASTER_KEY:
    AWS:
    access_key_id:
    secret_access_key:
    ```
    23 changes: 23 additions & 0 deletions B-config-unicorn.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,23 @@
    ```
    # Configures Unicorn with the location of your application, and the location of its socket, logs, and PIDs.
    # set path to application
    app_dir = File.expand_path("../..", __FILE__)
    shared_dir = "#{app_dir}/shared"
    working_directory app_dir
    # Set unicorn options
    worker_processes 2
    preload_app true
    timeout 30
    # Set up socket location
    listen "#{shared_dir}/sockets/unicorn.sock", :backlog => 64
    # Logging
    stderr_path "#{shared_dir}/log/unicorn.stderr.log"
    stdout_path "#{shared_dir}/log/unicorn.stdout.log"
    # Set master PID location
    pid "#{shared_dir}/pids/unicorn.pid"
    ```
    69 changes: 69 additions & 0 deletions C-UNICORN-INIT.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,69 @@
    #!/bin/sh

    ### BEGIN INIT INFO
    # Provides: unicorn
    # Required-Start: $all
    # Required-Stop: $all
    # Default-Start: 2 3 4 5
    # Default-Stop: 0 1 6
    # Short-Description: starts the unicorn app server
    # Description: starts unicorn using start-stop-daemon
    ### END INIT INFO

    set -e

    USAGE="Usage: $0 <start|stop|restart|upgrade|rotate|force-stop>"

    # app settings
    USER="deploy"
    APP_NAME="appname"
    APP_ROOT="/home/$USER/$APP_NAME"
    ENV="production"

    # environment settings
    PATH="/home/$USER/.rbenv/shims:/home/$USER/.rbenv/bin:$PATH"
    CMD="cd $APP_ROOT && bundle exec unicorn -c config/unicorn.rb -E $ENV -D"
    PID="$APP_ROOT/shared/pids/unicorn.pid"
    OLD_PID="$PID.oldbin"

    # make sure the app exists
    cd $APP_ROOT || exit 1

    sig () {
    test -s "$PID" && kill -$1 `cat $PID`
    }

    oldsig () {
    test -s $OLD_PID && kill -$1 `cat $OLD_PID`
    }

    case $1 in
    start)
    sig 0 && echo >&2 "Already running" && exit 0
    echo "Starting $APP_NAME"
    su - $USER -c "$CMD"
    ;;
    stop)
    echo "Stopping $APP_NAME"
    sig QUIT && exit 0
    echo >&2 "Not running"
    ;;
    force-stop)
    echo "Force stopping $APP_NAME"
    sig TERM && exit 0
    echo >&2 "Not running"
    ;;
    restart|reload|upgrade)
    sig USR2 && echo "reloaded $APP_NAME" && exit 0
    echo >&2 "Couldn't reload, starting '$CMD' instead"
    $CMD
    ;;
    rotate)
    sig USR1 && echo rotated logs OK && exit 0
    echo >&2 "Couldn't rotate logs" && exit 1
    ;;
    *)
    echo >&2 $USAGE
    exit 1
    ;;
    esac
    24 changes: 24 additions & 0 deletions D-NGINX-REV-PROXY.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,24 @@
    upstream app {
    # Path to Unicorn SOCK file, as defined previously
    server unix:/home/deploy/<APPNAME>/shared/sockets/unicorn.sock fail_timeout=0;
    }

    server {
    listen 80;
    server_name localhost;

    root /home/deploy/<APPNAME>/public;

    try_files $uri/index.html $uri @app;

    location @app {
    proxy_pass http://app;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    }

    error_page 500 502 503 504 /500.html;
    client_max_body_size 4G;
    keepalive_timeout 10;
    }
  5. @aquaflamingo aquaflamingo created this gist Aug 15, 2018.
    505 changes: 505 additions & 0 deletions Ubuntu-16-Nginx-Unicorn-Rails-DO.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,505 @@
    # 🚂 Deploy Ubuntu 16.04 Rails Server on Digital Ocean

    using Unicorn, Nginx, PostgreSQL, active_storage, Amazon S3. Combined summary of all guides.

    ## 💧 1. Basic Droplet/SSH Set Up

    ### Create Droplet: Ubuntu 16.04

    Your `root` password is e-mailed to you.

    ### Create SSH Key [[Guide]](https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/create-with-openssh/)

    Enter `.ssh` directory:

    ```$ cd ~/.ssh```

    Generate Key:

    ```$ ssh-keygen```

    Save DigitalOcean (`DO`) key with created `key-password`

    ```$ ~/.ssh/id_do_mac```

    *Save `key-password` in password manager*

    ### Add Public Key To Digital Ocean [[Guide]](https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/to-account/)

    Copy public key to clip board:

    ```$ cat ~/.ssh/id_do_mac.pub | pbcopy```

    Add SSH Key to Digital Ocean Account Name `MacOS`:

    `Home>Security>Add SSH Key`

    ----

    ## 💻 2. Initial Server Setup [[Guide]](https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-16-04)

    ### Create Non Root User

    ```
    $ ssh root@your_server_ip
    $ adduser deploy
    ```

    Create `deploy-password` add to password manager.

    Give `deploy` root privileges:

    ```
    $ usermod -aG sudo deploy
    ```

    ### Add Public Key Auth to Your Server

    Use already created **local** SSH key and add to the server.

    ```
    ## Local Machine
    $ cat ~/.ssh/id_do_mac.pub | pbcopy
    ```

    Paste SSH Key to Deployed User's Authorized Keys
    ```
    ## Server
    $ su - deploy
    $ mkdir ~/.ssh
    $ chmod 700 ~/.ssh
    $ nano ~/.ssh/authorized_keys
    # Paste Key
    ```

    Change permissions back:
    ```
    $ chmod 600 ~/.ssh/authorized_keys
    ```

    ### Remove Password Auth
    ```
    $ sudo nano /etc/ssh/sshd_config
    ```

    Find: `PasswordAuthentication` change to

    ```
    PasswordAuthentication no
    ```

    Reload: `sudo systemctl reload sshd`

    Test Login: `ssh deploy@server_ip`

    ### Add Firewall

    ```
    $ sudo ufw allow OpenSSH
    $ sudo ufw enable
    # Enter: y
    $ sudo ufw status
    # Status: active
    ```
    ----
    ## 💎 3. Install Ruby on Rails & rbenv [[Guide]](https://www.digitalocean.com/community/tutorials/how-to-install-ruby-on-rails-with-rbenv-on-ubuntu-16-04)

    Login as `deploy` (i.e. `ssh deploy@server_ip` or `su - deploy`)

    ### Add dependencies, rbenv & rails
    Install `nodejs` dependence for Asset Pipeline

    ```
    $ curl -sL https://deb.nodesource.com/setup_8.x -o nodesource_setup.sh
    $ sudo bash nodesource_setup.sh
    $ sudo apt-get install nodejs
    $ nodejs -v
    # Output: v8.10.0
    ```

    Ruby + `rbenv` dependencies`

    ```
    $ sudo apt-get update
    $ sudo apt-get install autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm3 libgdbm-dev
    ```

    Add `rbenv` & `ruby-build`
    ```
    $ git clone https://github.com/rbenv/rbenv.git ~/.rbenv
    $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
    $ echo 'eval "$(rbenv init -)"' >> ~/.bashrc
    $ source ~/.bashrc
    $ type rbenv
    # output: ...
    $ git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
    ```

    Install `ruby 2.5.0` & gems
    ```
    $ rbenv install 2.5.0
    $ rbenv global 2.5.0
    $ echo "gem: --no-document" > ~/.gemrc
    # No Docs
    $ gem install bundler
    $ gem install rails
    # rails -v: Rails 5.2
    ```
    ----
    ## 🐘 4. Add PostgreSQL

    Add dependencies:
    ```
    $ sudo apt-get install postgresql postgresql-contrib libpq-dev
    ```

    Create user (this will be same user in your `database.yml`, `username` field for the `production` tag):
    ```
    $ sudo -u postgres createuser -s <APPNAME>
    ```

    Set password for `APPNAME`
    ```
    $ sudo -u postgres psql
    $ \password <APPNAME>
    ```
    **Save Postgres User and Password in password manager**

    ## 🔑 5. Rails Encrypted Credentials & Active Storage
    (for Database Keys, S3 and Secrets)

    **ON SERVER**:

    Install [`rbenv-vars`](https://www.digitalocean.com/community/tutorials/how-to-deploy-a-rails-app-with-unicorn-and-nginx-on-ubuntu-14-04#install-rbenv-vars-plugin) for environment variable management.
    ```
    $ cd ~/.rbenv/plugins
    $ git clone https://github.com/sstephenson/rbenv-vars.git
    ```

    **ON LOCAL TERMINAL/PROJECT**:

    Generate `config/master.key` for [Rails Encrypted Credentials](https://www.engineyard.com/blog/rails-encrypted-credentials-on-rails-5.2) by editing credentials

    ```
    bin/rails credentials:edit
    # generates credentials.yml.enc
    ```

    ### Adding Postgres Database
    Add the postgres production database password to `credentials.yml.enc`.
    ```
    ## credentials.ymc.enc
    database:
    production_password: <PASSWORD-CREATED-IN-STEP-3-ABOVE>
    ```

    Edit `database.yml`

    ```
    ## database.yml
    production:
    adapter: postgresql
    encoding: unicode
    database: <APPNAME_production>
    host: localhost
    pool: 5
    username: <APPNAME-CREATED-IN-STEP-3-ABOVE>
    password: <%= Rails.application.credentials.dig(:database, :production_password) %>
    ## ...
    ```

    Copy the `RAILS_MASTER_KEY` from `config/master.key`. *Save RAILS_MASTER_KEY in Password Manager*
    ```
    $ cat config/master.key
    # cfda33e2583...
    ```

    **ON SERVER:**

    Edit `rbenv-vars` to add the `RAILS_MASTER_KEY` (because Encrypted Credentials looks for `ENV['RAILS_MASTER_KEY']`)
    ```
    $ nano .rbenv-vars
    ```

    ```
    ## .rbenv-vars
    RAILS_MASTER_KEY=<MASTER-KEY-HERE>
    ```

    ### Adding Amazon S3
    1. [Create S3 Bucket](https://docs.aws.amazon.com/quickstarts/latest/s3backup/step-1-create-bucket.html)

    2. [Create an S3 Access Key](https://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html) - *Save ACCESS_KEY_ID and SECRET_ACCESS_KEY in Password Manager*

    **ON LOCAL TERMINAL/PROJECT**:

    Add S3 Keys to Encrypted Credentials
    ```
    bin/rails credentials:edit
    ```

    ```
    # credentials.yml.enc
    aws:
    access_key_id: <s3_key_id>
    secret_access_key: <s3_secret>
    ```

    Edit `storage.yml`

    ```
    ## storage.yml
    amazon:
    service: S3
    access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
    secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
    region: us-east-1
    bucket: <%= Rails.application.credentials.dig(:aws, :bucket) %>
    ## ...
    ```

    Add, Commit & Push Changes to Remote Repo
    ```
    $ git add -A
    $ git commit -m "Add and encrypt deploy credentials"
    $ git push origin master
    ```

    **ON SERVER**:

    Pull Git Repo with Rails app:
    ```
    $ git clone https://github.com/username/repo
    $ bundle install
    # Installed
    ```

    ### Build Database, and Production Environment
    ```
    $ RAILS_ENV=production rake db:create
    $ RAILS_ENV=production rake db:migrate
    $ RAILS_ENV=production rake assets:precompile
    $ RAILS_ENV=production rails server --binding=server_public_IP
    # test http://server_ip:3000
    ```

    If test fails allow firewall to port 3000 temporarily[1](https://www.digitalocean.com/community/questions/rails-binding-to-ip-3000-is-giving-me-connection-timeout?comment=72308):
    ```
    $ sudo ufw allow 3000
    ```

    ----
    ## 🦄 6. Installing Unicorn [[Guide]](https://www.digitalocean.com/community/tutorials/how-to-deploy-a-rails-app-with-unicorn-and-nginx-on-ubuntu-14-04#configure-unicorn)

    Add `gem 'unicorn'` to `Gemfile` and `bundle`.

    Edit `config/unicorn.rb` paste [**Appendix B: config/unicorn.rb**](B-config-unicorn.md)

    Save and add logging to Rails App:
    ```
    $ mkdir -p shared/pids shared/sockets shared/log
    ```

    Edit and add unicorn init script from [**Appendix C: Unicorn Init Script**:](C-UNICORN-INIT.md)
    ```
    $ sudo nano /etc/init.d/unicorn_APPNAME
    ```

    **Ensure You Change APPNAME in Init Script to actual app**

    Update permissions for init script:
    ```
    $ sudo chmod 755 /etc/init.d/unicorn_appname
    $ sudo update-rc.d unicorn_appname defaults
    ```

    Run via:

    ```
    sudo service unicorn_appname start
    ```

    If run fails and `systemctl` reveals little, ensure that you `rbenv`'s installation added the `RBENV_ROOT` properly. Otherwise edit your `deploy` `~/.profile` file and [add](https://stackoverflow.com/questions/31971806/unicorn-service-upstart-script-throws-su-bundle-command-not-found) the following and resart the service.

    ```
    $ export RBENV_ROOT=/home/YOUR_USER_PATH/.rbenv
    $ export PATH=$RBENV_ROOT/shims:$RBENV_ROOT/bin:$PATH
    ```

    ----
    ## 🎡 7. Installing NGINX Reverse Proxy [[Guide]](https://www.digitalocean.com/community/tutorials/how-to-deploy-a-rails-app-with-unicorn-and-nginx-on-ubuntu-14-04#install-and-configure-nginx)

    ```
    $ sudo apt-get install nginx
    ```

    Add NGINX reverse proxy config with block in [**Appendix D: NGINX Reverse Proxy**](D-NGINX-REV-PROXY.md)

    ```
    $ sudo vi /etc/nginx/sites-available/default
    ```

    **Ensure You Change APPNAME in NGINX to actual app**

    Restart NGINX

    ```
    $ sudo service nginx restart
    # try: http://server_public_IP
    ```
    ----
    ## 🙀 8. Complete

    Make sure you have all passwords: [**Appendix A: Inside Password Manager**](A-INSIDE-PW-MANAGER.md)

    All System Operational.

    <img src="https://i.imgur.com/wIevyxb.jpg" height="300px"/>


    ## Appendix:
    ### A. Inside Password Manager:
    ```
    Digital_Ocean:
    root_pass:
    deploy_pass:
    Postgres:
    appname:
    appname_password:
    Rails_Credentials
    RAILS_MASTER_KEY:
    AWS:
    access_key_id:
    secret_access_key:
    ```

    ### B. [config/unicorn.rb](https://www.digitalocean.com/community/tutorials/how-to-deploy-a-rails-app-with-unicorn-and-nginx-on-ubuntu-14-04)
    ```
    # Configures Unicorn with the location of your application, and the location of its socket, logs, and PIDs.
    # set path to application
    app_dir = File.expand_path("../..", __FILE__)
    shared_dir = "#{app_dir}/shared"
    working_directory app_dir
    # Set unicorn options
    worker_processes 2
    preload_app true
    timeout 30
    # Set up socket location
    listen "#{shared_dir}/sockets/unicorn.sock", :backlog => 64
    # Logging
    stderr_path "#{shared_dir}/log/unicorn.stderr.log"
    stdout_path "#{shared_dir}/log/unicorn.stdout.log"
    # Set master PID location
    pid "#{shared_dir}/pids/unicorn.pid"
    ```

    ### C. [Unicorn Init Script](https://www.digitalocean.com/community/tutorials/how-to-deploy-a-rails-app-with-unicorn-and-nginx-on-ubuntu-14-04)
    **Replace APPNAME**
    ```
    #!/bin/sh
    ### BEGIN INIT INFO
    # Provides: unicorn
    # Required-Start: $all
    # Required-Stop: $all
    # Default-Start: 2 3 4 5
    # Default-Stop: 0 1 6
    # Short-Description: starts the unicorn app server
    # Description: starts unicorn using start-stop-daemon
    ### END INIT INFO
    set -e
    USAGE="Usage: $0 <start|stop|restart|upgrade|rotate|force-stop>"
    # app settings
    USER="deploy"
    APP_NAME="appname"
    APP_ROOT="/home/$USER/$APP_NAME"
    ENV="production"
    # environment settings
    PATH="/home/$USER/.rbenv/shims:/home/$USER/.rbenv/bin:$PATH"
    CMD="cd $APP_ROOT && bundle exec unicorn -c config/unicorn.rb -E $ENV -D"
    PID="$APP_ROOT/shared/pids/unicorn.pid"
    OLD_PID="$PID.oldbin"
    # make sure the app exists
    cd $APP_ROOT || exit 1
    sig () {
    test -s "$PID" && kill -$1 `cat $PID`
    }
    oldsig () {
    test -s $OLD_PID && kill -$1 `cat $OLD_PID`
    }
    case $1 in
    start)
    sig 0 && echo >&2 "Already running" && exit 0
    echo "Starting $APP_NAME"
    su - $USER -c "$CMD"
    ;;
    stop)
    echo "Stopping $APP_NAME"
    sig QUIT && exit 0
    echo >&2 "Not running"
    ;;
    force-stop)
    echo "Force stopping $APP_NAME"
    sig TERM && exit 0
    echo >&2 "Not running"
    ;;
    restart|reload|upgrade)
    sig USR2 && echo "reloaded $APP_NAME" && exit 0
    echo >&2 "Couldn't reload, starting '$CMD' instead"
    $CMD
    ;;
    rotate)
    sig USR1 && echo rotated logs OK && exit 0
    echo >&2 "Couldn't rotate logs" && exit 1
    ;;
    *)
    echo >&2 $USAGE
    exit 1
    ;;
    esac
    ```
    ### D. [NGINX Reverse Proxy](https://www.digitalocean.com/community/tutorials/how-to-deploy-a-rails-app-with-unicorn-and-nginx-on-ubuntu-14-04)
    **Replace APPNAME**
    ```
    upstream app {
    # Path to Unicorn SOCK file, as defined previously
    server unix:/home/deploy/<APPNAME>/shared/sockets/unicorn.sock fail_timeout=0;
    }
    server {
    listen 80;
    server_name localhost;
    root /home/deploy/<APPNAME>/public;
    try_files $uri/index.html $uri @app;
    location @app {
    proxy_pass http://app;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    }
    error_page 500 502 503 504 /500.html;
    client_max_body_size 4G;
    keepalive_timeout 10;
    }
    ```