Skip to content

Instantly share code, notes, and snippets.

@dinushchathurya
Created April 23, 2022 02:41
Show Gist options
  • Save dinushchathurya/12c6c2e958d8cbd359f0769d4e85ab32 to your computer and use it in GitHub Desktop.
Save dinushchathurya/12c6c2e958d8cbd359f0769d4e85ab32 to your computer and use it in GitHub Desktop.
Deploy NodeJS using GitLab CI-CD
Deploy nodejs app with gitlab.com and pm2
=========================================
This manual is about setting up an automatic deploy workflow using [nodejs](https://nodejs.org/en/),
[PM2](http://pm2.keymetrics.io/), [nginx](https://nginx.org/) and
[GitLab CI](https://about.gitlab.com/features/gitlab-ci-cd/). 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")
Configure target server
-----------------------
### 1. Create new sudo-user
Login with SSH user "root " and run:
```bash
adduser ubuntu
usermod -aG sudo ubuntu
```
To check sudo access run:
```bash
su ubuntu
sudo ls -la /root
```
### 2. Install nodejs and npm
You can find official instruction
[here](https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions).
For Ubuntu 16.04 run:
```bash
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install -y nodejs
```
To check an installation run:
```bash
node -v
npm -v
```
### 3. Install process manager pm2
[PM2](http://pm2.keymetrics.io/) is a beautiful production process manager for nodejs. It will observe, log and
automatically restart your application if it fall. Run now:
```bash
sudo npm install -g pm2@latest
```
To enable auto start pm2 on reboot run:
```bash
pm2 startup
```
then **(!important)** follow the instructions on your screen (run displayed command).
### 4. Install git
```bash
sudo apt-get install git -y
```
If you haven't deploy git keys yet, you should run:
```bash
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
```
This command will generate private (`/home/ubuntu/.ssh/id_rsa`) and public
(`/home/ubuntu/.ssh/id_rsa.pub`) key. Print public key:
```bash
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:
```bash
ssh -T git@gitlab.com
```
On the question "The authenticity of host...?" answer "yes".
If all is okay, you should see string like *"Welcome to GitLab, yourUsername!"*.
### 5. Generate SSH keys for current server
Now we should generate SSH keys to access current server without password.
Run next command again, but set file path to `/home/ubuntu/access`:
```bash
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
```
This command will generate private (`/home/ubuntu/access`) and public (`/home/ubuntu/access.pub`) key.
Move new generated key to *authorized_keys*:
```bash
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:
```bash
cat ~/access
```
### 6. Install nginx
```bash
sudo apt-get install nginx -y
sudo rm /etc/nginx/sites-enabled/default
```
Open nginx config:
```bash
sudo nano /etc/nginx/sites-available/app
```
and replace it with:
```nginx
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:
```bash
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"):
```bash
sudo systemctl status nginx
```
Configure deployment with Gitlab CI
-----------------------------------
### 1. Create file `ecosystem.config.js`in root directory of your project:
```javascript
// 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 = 'git@gitlab.com: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'
}
}
};
```
### 2. Add secret variables in gitlab:
Go to [gitlab.com](https:/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 |
### 3. Create file `.gitlab-ci.yml` in root directory of project:
```yaml
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment