This manual is about setting up an automatic deploy workflow using nodejs, PM2, nginx and GitLab CI. It is tested on:
- Target server: Ubuntu 16.04 x64. This is suitable for Ubuntu 14.x.
- Windows 10 on my PC to work.
I use Alpine Linux in Docker container (gitlab) to speed up deployment.
What do we need:
- Account on gitlab.com
- New virtual server with Ubuntu 16.04 x64 (or 14.x) to run application (i will call it the "target server")
Login with SSH user "root " and run:
adduser ubuntu
usermod -aG sudo ubuntu
To check sudo access run:
su ubuntu
sudo ls -la /root
You can find official instruction here.
For Ubuntu 16.04 run:
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install -y nodejs
To check an installation run:
node -v
npm -v
PM2 is a beautiful production process manager for nodejs. It will observe, log and automatically restart your application if it fall. Run now:
sudo npm install -g pm2@latest
To enable auto start pm2 on reboot run:
pm2 startup
then (!important) follow the instructions on your screen (run displayed command).
sudo apt-get install git -y
If you haven't deploy git keys yet, you should run:
ssh-keygen -t rsa -b 4096 -C "[email protected]"
This command will generate private (/home/ubuntu/.ssh/id_rsa
) and public
(/home/ubuntu/.ssh/id_rsa.pub
) key. Print public key:
cat /home/ubuntu/.ssh/id_rsa.pub
copy it clipboard and paste to gitlab (Repo settings / Tab "Repository" / Deploy Keys).
Check ssh access to repository:
ssh -T [email protected]
On the question "The authenticity of host...?" answer "yes". If all is okay, you should see string like "Welcome to GitLab, yourUsername!".
Now we should generate SSH keys to access current server without password.
Run next command again, but set file path to /home/ubuntu/access
:
ssh-keygen -t rsa -b 4096 -C "[email protected]"
This command will generate private (/home/ubuntu/access
) and public (/home/ubuntu/access.pub
) key.
Move new generated key to authorized_keys:
cat /home/ubuntu/access.pub >> ~/.ssh/authorized_keys
You must copy and save private key on your computer. To print this key on screen use:
cat ~/access
sudo apt-get install nginx -y
sudo rm /etc/nginx/sites-enabled/default
Open nginx config:
sudo nano /etc/nginx/sites-available/app
and replace it with:
server {
listen 80;
server_name app;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://127.0.0.1:3000;
proxy_redirect off;
proxy_buffering off;
}
}
Then run:
sudo ln -s /etc/nginx/sites-available/app /etc/nginx/sites-enabled/app
sudo systemctl restart nginx
# Note: for Ubuntu 14.x run instead: sudo service nginx restart
And check nginx status (it should be "active"):
sudo systemctl status nginx
// Target server hostname or IP address
const TARGET_SERVER_HOST = process.env.TARGET_SERVER_HOST ? process.env.TARGET_SERVER_HOST.trim() : '';
// Target server username
const TARGET_SERVER_USER = process.env.TARGET_SERVER_USER ? process.env.TARGET_SERVER_USER.trim() : '';
// Target server application path
const TARGET_SERVER_APP_PATH = `/home/${TARGET_SERVER_USER}/app`;
// Your repository
const REPO = '[email protected]:yourUsername/test-server.git';
module.exports = {
/**
* Application configuration section
* http://pm2.keymetrics.io/docs/usage/application-declaration/
*/
apps: [
{
name: 'testApp',
script: 'index.js',
env: {
NODE_ENV: 'development'
},
env_production: {
NODE_ENV: 'production',
PORT: 3000
}
}
],
/**
* Deployment section
* http://pm2.keymetrics.io/docs/usage/deployment/
*/
deploy: {
production: {
user: TARGET_SERVER_USER,
host: TARGET_SERVER_HOST,
ref: 'origin/master',
repo: REPO,
ssh_options: 'StrictHostKeyChecking=no',
path: TARGET_SERVER_APP_PATH,
'post-deploy': 'npm install --production'
+ ' && pm2 startOrRestart ecosystem.config.js --env=production'
+ ' && pm2 save'
}
}
};
Go to gitlab.com -> Your project -> "Settings" -> "CI/CD" -> "Secret variables". Add some variables:
Variable | Description |
---|---|
TARGET_SERVER_HOST | Target server host like 127.0.0.1 or your.host.com |
TARGET_SERVER_USER | SSH username for login. Example ubuntu |
TARGET_SERVER_SECRET_KEY_BASE64 | Base64 encoded private RSA key to login target server. Make it protected |
image: keymetrics/pm2:6
stages:
- deploy
deploy_prod:
stage: deploy
script:
- echo "====== Deploy to production server ======"
- apk update && apk upgrade
- apk add git openssh bash
# Add target server`s secret key
- mkdir ~/.ssh
- echo $TARGET_SERVER_SECRET_KEY_BASE64 | base64 -d > ~/.ssh/id_rsa
- chmod 700 ~/.ssh && chmod 600 ~/.ssh/*
- echo "Test ssh connection"
- ssh -o StrictHostKeyChecking=no -T "ubuntu@$TARGET_SERVER_HOST"
# Delploy
- echo "Setup tagget server directories"
- pm2 deploy ecosystem.config.js production setup 2>&1 || true
- echo "make deploy"
- pm2 deploy ecosystem.config.js production
environment:
name: deploying
only:
- master
If all is okay, your project will be automatically deployed every push and merge to master branch.
You probably should replace "ubuntu" by $TARGET_SERVER_USER in order to respect configuration files.
Anyway, thank you for the tutorial !