Skip to content

Instantly share code, notes, and snippets.

@changx03
Last active May 19, 2019 16:25
Show Gist options
  • Save changx03/320dc3ec18cdf86b22e878da422de114 to your computer and use it in GitHub Desktop.
Save changx03/320dc3ec18cdf86b22e878da422de114 to your computer and use it in GitHub Desktop.
Creating a new user on Linux

Creating a new user on Linux

I prefer to use cmder on Windows. It provides most comment linux commends out of the box.

Create a node.js project

# install express-generator
npm install -g express-generator

# create new express project
# use hogan.js and sass
express --view=hjs --css=sass node-app

# install package
cd node-app
yarn

# start server
yarn start

Testing the server by browsing http://localhost:3000 using Chrome Or curl http://localhost:3000 from terminal

Create Vagrant virtual box

# create a folder to save vagrant vm profile
mkdir vagrant

# install Vagrant box
# https://app.vagrantup.com/boxes/
vagrant box add ubuntu/xenial64
vagrant init ubuntu/xenial64

# start vm
vagrant up
vagrant status

# login vm
vagrant ssh

Edit the generated Vagrantfile, change language mode to Ruby

In Vagrantfile

# -*- mode: ruby -*-
# vi: set ft=ruby :

$script = <<-SCRIPT
#!/bin/bash

echo "Starting Provision..."
sudo apt-get update

echo "Installing nginx..."
sudo apt-get install nginx -y

echo "Installing nodejs..."
curl -sL https://deb.nodesource.com/setup_10.x -o nodesource_setup.sh
sudo bash nodesource_setup.sh
sudo apt-get install nodejs -y

echo "Installing yarn..."
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update
sudo apt-get install yarn -y

echo "Installing pm2..."
sudo npm -g install pm2

echo "Provision completed"
SCRIPT

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/xenial64"

  config.vm.network "private_network", ip: "10.0.0.10"
  config.vm.provision "shell" do |s|
    s.inline = $script
  end
end

Create user

From remote

# add a user called "luke"
sudo adduser luke

# switch to user
sudo su - luke

whoami

# create SSH connection
cd ~
mkdir .ssh
# 700 owner can read, write and execute
chmod 700 .ssh

# do NOT change the file name, `authorized_keys`
touch .ssh/authorized_keys

# owner can read and write
chmod 600 .ssh/authorized_keys

Copy the public key to .ssh/authorized_keys file

From local machine, on Windows

cat C:\Users\<username>\.ssh\id_rsa.pub

On Mac

cat ~/.ssh/id_rsa.pub

From vm

# paste your public key using vim
vim ~/.ssh/authorized_keys

Login as new user

ssh luke@<ip_address>

Create a compressed file to upload our project

# tar compress, zip, file <output_filename>.tar.gz files...
tar czf test-app.tar.gz app.js bin package.json public routes views

Copy file from local to remote

scp test##app.tar.gz luke@55.55.55.55:~

Extract file from remote

# create a folder
mkdir test-app

# tar eXtract, file <compressed_file> -C (speCified directory) <folder>
tar xf test-app.tar.gz -C test-app

Start node server

DEBUG=test-node-app:server NODE_ENV=development PORT=8081 yarn start

Configurate PM2

# require log in as root
sudo npm install -g pm2

Create config file

touch pm2.config.js
vim pm2.config.js

In pm2.config.js

module.exports = {
  apps: [
    {
      name: 'node-demo',
      script: './bin/www',
      watch: false, // pm2 kills and restarts your application without indication!
      instances: 'max',
      exec_mode: 'cluster',
      env: {
        PORT: 3001,
        NODE_ENV: 'production'
      },
      env_dev: {
        DEBUG: 'node-demo:server',
        PORT: 3001,
        NODE_ENV: 'development'
      }
    }
  ]
}

Start pm2

pm2 start pm2.config.js

# Check current running processes
pm2 list

Run pm2 as a service

# generate startup script
# provide user and home path
pm2 startup systemd -u luke --hp /home/luke

Returns

sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u luke --hp /home/luke

Save your pm2 configuration!

pm2 save

Test pm2 by rebooting the server

sudo reboot

Automated deployment

# create deploy script
touch deploy.sh

# give it execute right
chmod +x deploy.sh

# run it
./deploy.sh

In deploy.sh file

#!/bin/bash

echo "Creating zip file and copying to remove..."
tar czf app.tar.gz bin public routes views app.js package.json pm2.config.js yarn.lock
scp app.tar.gz luke@10.0.0.10:~
rm app.tar.gz

echo "Login to remove..."
# the command afterward will be executed on remote
ssh luke@10.0.0.10 << 'ENDSSH'
pm2 stop node-demo
pm2 delete node-demo
echo "pm2 is stopped"
rm -rf app
mkdir app
tar xf app.tar.gz -C app
rm app.tar.gz
cd app
yarn
echo "Starting pm2..."
pm2 start pm2.config.js
pm2 save
ENDSSH

Setup nginx as a Reverse Proxy (listening on Port 80)

  • Only root can access Port 80, so the deploy user doesn't have access.

What can nginx do?

  • HTTPS
  • Listening on Port 80, reverse proxy to node.js server
  • Serve static files
  • Load balancing

nginx setup

Login remote as root

sudo apt-get update && sudo apt-get install nginx -y

cd /etc/nginx/sites-available
sudo vim default

In /etc/nginx/nginx.conf

The # of cores your CPU is running

worker_processes: auto;

Check the # of cores

cat /proc/cpuinfo

Add proxy configuration into server block in /etc/nginx/sites-available/default file

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /var/www/html;

        # Add index.php to the list if you are using PHP
        index index.html index.htm index.nginx-debian.html;

        server_name _;

        location / {
                proxy_pass http://localhost:3001;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection 'upgrade';
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
        }
}

To map another url, e.g. http://dev.mynodeapp.com/app2

server {
  ...
  location / {
    ...
  }

  location /app2 {
    proxy_pass http://localhost:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
  }
}

Testing current configuration

sudo nginx -t

Restart nginx

sudo systemctl restart nginx

Testing with Apache Bench

ab -c 40 -n 1000 http://10.0.0.10/

Shutdown Vagrant VM

From vagrant folder

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