Skip to content

Instantly share code, notes, and snippets.

@werelax
Last active April 5, 2020 14:21
Show Gist options
  • Save werelax/3561d40847472e3a0efae22c4277e0e7 to your computer and use it in GitHub Desktop.
Save werelax/3561d40847472e3a0efae22c4277e0e7 to your computer and use it in GitHub Desktop.
Privision a node server

The first steps

Change the root password (to get a good password: http://passwordsgenerator.net/) and create a non root user:

useradd -m -s /bin/bash not_root
passwd not_root
apt-get update; apt-get install -y nginx sudo

Setup your user's permissions

vim /etc/sudoers

and change the line starting with %sudo (permissions for members of the sudo group) to:

%sudo   ALL=(ALL) NOPASSWD:ALL

and then:

usermod -a -G sudo not_root

Install node.js on Ubuntu

curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt-get install -y nodejs build-essential

Node tools

npm install -g pm2

Setup NGINX

vim /etc/nginx/sites-available/your.site.com
upstream app_server {
  server 127.0.0.1:8000;
  keepalive 64;
}

server {
  listen 80;
  listen 443 ssl;

  server_name your.site.com;
  ssl_certificate /etc/letsencrypt/live/your.site.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/your.site.com/privkey.pem;

  if ($scheme = http) {
    return 301 https://$server_name$request_uri;
  }
  
  # error_page 502  /errors/502.html;

  root /var/www/site/static/;
  # only proxy if no static file is found
  try_files $uri $uri/ @gateway;
  access_log off;
  expires max;
  
  location / {
    proxy_redirect off;
    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;
    proxy_set_header   Host                   $http_host;
    proxy_set_header   Connection "";
    proxy_http_version 1.1;
    proxy_cache_key    sfs$request_uri$scheme;
    proxy_pass         http://app_server;
  }
  
  location @gateway {
    proxy_redirect off;
    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;
    proxy_set_header   Host                   $http_host;
    proxy_set_header   Connection "";
    proxy_http_version 1.1;
    proxy_cache_key    sfs$request_uri$scheme;
    proxy_pass         http://app_server;
  }
}

and then:

cd /etc/nginx/sites-enabled
ln -s ../sites-available/your.site.com
service nginx restart

Setup SSL

Using certbot:

apt-get install -y letsencrypt 

and then:

service nginx stop
letsencrypt certonly --standalone -d your.site.com

fill the required info and then, after a successful registration, run:

crontab -e

and add this line at the end to keep the cert up to date (run every hour):

0 * * * * letsencrypt renew

After all that:

service nginx start

Generate ssh key pair

Form your machine:

ssh-keygen -t rsa -b 2048 -v

and enter key when prompted for the location. Then (only on OSX: brew install ssh-copy-id):

ssh-copy-id -i ./key.pub not_root@your.site.com

and use the password to auth yourself just this time. You may have to brew install ssh-copy-id if on a mac. From now on, you're going to use the private key to log in.

mv key your-site-com.pem
ssh -i ./your-site-com.pem not_root@your.site.com

Setup your project's repo

Log to the server as the non-root user and clone your repo (you may need to add the machine's ssk key to your git hosting service):

ssh -i ./your-site-com.pem not_root@your.site.com
cd sites
git clone git@gitjat.com:werelax/my-cool-project.git my-cool-project
sudo ln -s /home/not_root/sites/my-cool-project /var/www/site

Setup your deploy scripts

Using flightplan (install it as a global command, and add pm2 to package.json), create a flightplan.js similar to:

'use strict';

const plan = require('flightplan');

// -------------------------
// Targets

plan.target('production', {
  host: 'your.site.com',
  username: 'not_root',
  privateKey: '../config/your-site-com.pem',
});

// -------------------------
// Tasks

plan.remote('stop', (remote) => {
  remote.with('cd /var/www/site/', () => {
    remote.log('* Stop the server');
    remote.exec('./node_modules/.bin/pm2 stop 0');
  });
});

plan.remote('start', (remote) => {
  remote.with('cd /var/www/site/', () => {
    remote.log('* Start the server');
    remote.exec('./node_modules/.bin/pm2 start src/index.js');
  });
});

plan.remote('deploy', (remote) => {
  remote.with('cd /var/www/site/', () => {
    remote.log('* Pull updates');
    remote.exec('git pull origin master --ff-only');

    remote.log('* Update dependencies');
    remote.exec('npm install');

    remote.log('* Stop the server');
    remote.exec('./node_modules/.bin/pm2 stop 0 || true');

    remote.log('* Start the server');
    remote.exec('./node_modules/.bin/pm2 start src/index.js');
  });
});

plan.remote('default', ['start', 'deploy', 'stop']);

And then run (from your local machine):

fly -f flightplan.js deploy:production

and, hopefully, you're done!

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