Skip to content

Instantly share code, notes, and snippets.

@dunguyenn
Forked from pilotpirxie/DigitalOcean.md
Created November 15, 2022 17:32
Show Gist options
  • Save dunguyenn/8beaaa4e3d0f8116a54fe24530ca4d8d to your computer and use it in GitHub Desktop.
Save dunguyenn/8beaaa4e3d0f8116a54fe24530ca4d8d to your computer and use it in GitHub Desktop.
Node.js + Nginx + Redis + MySQL + PM2 configuration on DigitalOcean

Node.js + Nginx + Redis + MySQL + PM2 configuration on DigitalOcean

Installation

  1. Install LEMP stack
  2. Overwrite /etc/nginx/nginx.conf
# /etc/nginx/nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 768;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    server_tokens off;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
    charset utf-8;
    log_not_found off;

    add_header X-XSS-Protection 1;
    add_header X-Content-Type-Options nosniff;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;
    add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
    add_header X-Frame-Options "SAMEORIGIN" always;

    add_header Last-Modified $date_gmt;
    add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
    if_modified_since off;
    expires off;
    etag off;

    client_body_buffer_size 1K;
    client_header_buffer_size 1k;
    client_max_body_size 50k;
    large_client_header_buffers 2 1k;

    client_body_timeout 20;
    client_header_timeout 10;
    send_timeout 10;
    proxy_no_cache 1;
    proxy_cache_bypass 1;

    limit_conn_zone $binary_remote_addr zone=addr:5m;

    gzip on;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}
  1. Add new server block in /etc/nginx/sites-available/default
# /etc/nginx/sites-available/default

server {
    listen 80;
    server_name localhost;
    limit_conn addr 5;

    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Host $remote_addr;
    proxy_http_version 1.1;

    # First reverse proxy
    location /api/ {
        proxy_pass http://localhost:8080;
    }

    # Second reverse proxy
    location / {
        proxy_pass http://localhost:3000;
    }

    # Allowed http methods
    if ($request_method !~ ^(GET|HEAD|POST|DELETE|PUT|PATCH)$ ){
         return 405;
    }

    # Redirect server error pages to the static page /50x.html
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root html;
    }
}
  1. Create symbolic link between previously created server block and sites-enabled:
sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/
  1. Install Node.js and NPM
curl -sL https://deb.nodesource.com/setup_10.x -o nodesource_setup.sh
sudo bash nodesource_setup.sh
sudo apt install nodejs
nodejs -v
npm -v
  1. Install Redis
sudo apt install redis-server
  1. Open Redis configuration file and set settings
# /etc/redis/redis.conf

supervised systemd
bind 127.0.0.1 ::1
requirepass <SOME STRONG PASSWORD>
maxmemory 100mb
maxmemory-policy volatile-ttl
  1. Restart and test Redis service
systemctl restart redis.service
redis-cli
auth <SOME STRONG PASSWORD>
set test 1234
get test
  1. Install PM2 and setup autostart on reboot
npm install pm2 -g
pm2 startup systemd
systemctl status pm2-<username>
  1. Add new user with less privledges
adduser <username>
  1. Apply security fixes on MySQL
sudo mysql_secure_installation
  1. Set MySQL root password
mysql
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '<ROOT_PASSWORD>';
  1. Add new non-root user
CREATE USER '<USERNAME>'@'localhost' IDENTIFIED BY '<PASSWORD>';
  1. Add user privledges
GRANT ALL PRIVILEGES ON *.* TO 'rohs'@'localhost' WITH GRANT OPTION;
  1. Flush and check MySQL credentials
FLUSH PRIVILEGES;
SELECT user,authentication_string,plugin,host FROM mysql.user;
  1. Install phpMyAdmin
sudo apt update
sudo apt install phpmyadmin
# PRESS TAB (Nginx isn't on the list, so choose OK)
# Select YES
# Type password for new phpmyadmin user
# Confirm password
  1. Configure Nginx - create new snippet
sudo nano /etc/nginx/snippets/phpmyadmin.conf
  1. Paste inside
# /etc/nginx/snippets/phpmyadmin.conf

location /phpmyadmin {
    root /usr/share/;
    index index.php index.html index.htm;
    location ~ ^/phpmyadmin/(.+\.php)$ {
        try_files $uri =404;
        root /usr/share/;
        fastcgi_pass unix:/run/php/php7.2-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include /etc/nginx/fastcgi_params;
    }

    location ~* ^/phpmyadmin/(.+\.(jpg|jpeg|gif|css|png|js|ico|html|xml|txt))$ {
        root /usr/share/;
    }
}
  1. Include snippet in server block
# /etc/nginx/sites-available/default

include snippets/phpmyadmin.conf;
  1. Upgrade phpMyAdmin - create backup
sudo mv /usr/share/phpmyadmin/ /usr/share/phpmyadmin.bak
sudo mkdir /usr/share/phpmyadmin/
cd /usr/share/phpmyadmin/
sudo wget https://files.phpmyadmin.net/phpMyAdmin/4.8.5/phpMyAdmin-4.8.5-all-languages.tar.gz
sudo tar xzf phpMyAdmin-4.8.5-all-languages.tar.gz
ls
sudo mv phpMyAdmin-4.8.5-all-languages/* /usr/share/phpmyadmin
  1. Open vendor_config.php and change phpMyAdmin settings
# /usr/share/phpmyadmin/libraries/vendor_config.php

# ...
define('TEMP_DIR', '/var/lib/phpmyadmin/tmp/');
# ...
define('CONFIG_DIR', '/etc/phpmyadmin/');

  1. Cleanup and remove useless phpMyAdmin files
sudo rm /usr/share/phpmyadmin/phpMyAdmin-4.8.5-all-languages.tar.gz
sudo rm -rf /usr/share/phpmyadmin/phpMyAdmin-4.8.5-all-languages
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment