How to setup Node.js production application on Apache multiple virtual host server

When it comes to using Node.js on backend it’s quite different from what people used to do for PHP server configuration.

Process manager

First and most important is not to run your application directly with node app.js command instead use one of the following packages: forever, PM2, and some others. This will help maintain your Node application process and restart it if it crashes.

My own pick is PM2 as it’s the most popular and has lots of features, great app monitoring, easy installations and usage.

Installation is quite simple, just using npm or yarn package managers. You probably will install it globally under root user so it can be accessible for all server users.

[[email protected] ~]$ npm -g install pm2 
# Or
[[email protected] ~]$ yarn global add pm2 

Then switch to the user, your virtual host will be using, let’s call it theproject, and run pm2 startup

[[email protected] ~]$ pm2 startup

It will respond with a message like this:
[PM2] Init System found: systemd
[PM2] To setup the Startup Script, copy/paste the following command:

It will require to run command with root privileges, using sudo user or root user directly:

[[email protected] ~]$ <the command from pm2 startup here>

If everything is successful it will add a PM2 service that will run on the system boot under your user theproject. It’s not recommended to install pm2 pm2 startup under the root user directly as it will run all your application scripts under root user as well.

Then you will need to add PM2 process configuration file, it supports json, js, yaml formats, here is the simplest example, process.yaml file:

apps:
  - name: theproject
    script: app.js
    exec_mode: fork

Check more info about process file here.

To run your application, cd to your project folder, and run pm2 start process.yml

[[email protected] ~]$ cd theproject
[[email protected] theproject]$ pm2 start process.yml

It will start your application and print current status table.

To make sure your app will start again after server restart, run:

[[email protected] theproject]$ pm2 save

You can nicely monitor your app using command pm2 monit, check current list of apps pm2 list and view last log records pm2 logs. To get further insights into your app, go to https://keymetrics.io/ setup account and follow instructions, the functionality is really awesome and must have for any production project.

Apache configuration

When our app is up and running on server we actually need to access it somehow using our domain name and 80 port, yet our app is running on some port like 3000 and is available only on 127.0.0.1 (localhost) ip (if not, it might be a security issue).

On 80 port we already have Apache running, so we can use Apache as a reverse proxy for our application. For you you will need to make sure Apache has mod_proxy installed and enabled.

Apache Virtual host configuration will be following:

<VirtualHost *:80>
  ServerName theproject.com
  ServerAlias www.theproject.com
  ErrorLog /home/theproject/logs/error_log
  CustomLog /home/theproject/logs/access_log combined

  ProxyRequests Off
  ProxyPreserveHost On

  ProxyPass / http://localhost:3000/
  ProxyPassReverse / http://localhost:3000/

  # This is needed only if you want to use web sockets
  RewriteEngine On
  RewriteCond %{REQUEST_URI}  ^/socket.io            [NC]
  RewriteCond %{QUERY_STRING} transport=websocket    [NC]
  RewriteRule /(.*)           ws://localhost:3000/$1 [P,L]
</VirtualHost>

After restarting Apache you should be able to successfully access your app using your domain address http://theproject.com.

This configuration also supports socket.io in case you may use web sockets with your application, which is very common with Node apps.

Simple MySql daily and weekly backups on Linux

Recently I had a task to create automatic Mysql database backups daily and weekly and keep some number of those backups.

After some short googling I come up with a quite small and simple shell script that just works.

To make this happen we need few following steps:

  1. Create a new file in /etc/cron.daily/ folder with execute permission, supposed we switched to root user already
    touch /etc/cron.daily/db-backup-mydb
    chmod 700 /etc/cron.daily/db-backup-mydb
    vim /etc/cron.daily/db-backup-mydb
    

    I used 700 permission so only root user can read the file, cause it will store password to our database

  2. Press key “i” and paste the following code:

    #!/bin/sh
    
    # Setup some variables
    backupfolder="/home/myapp/backups"
    user="myapp"
    prefix="db_daily_"
    now="$(date +'%Y%m%d-%H%M%S')"
    filename="$prefix$now.sql.gz"
    
    fullpathbackupfile="$backupfolder/$filename"
    logfile="$backupfolder/"backup_log_"$(date +'%Y_%m')".txt
    
    # Do a backup
    echo "mysqldump started at $(date +'%Y-%m-%d %H:%M:%S')" >> "$logfile"
    mysqldump --user=myapp --password=mypass --default-character-set=utf8 --single-transaction together | gzip > "$fullpathbackupfile"
    echo "mysqldump finished at $(date +'%Y-%m-%d %H:%M:%S')" >> "$logfile"
    
    # Change file permission
    chown $user:$user "$fullpathbackupfile"
    chown $user:$user "$logfile"
    echo "file permission changed" >> "$logfile"
    
    # Delete backup files older than 8 days
    find "$backupfolder" -name $prefix* -mtime +8 -exec rm {} \;
    echo "old files deleted" >> "$logfile"
    echo "operation finished at $(date +'%Y-%m-%d %H:%M:%S')" >> "$logfile"
    echo "*****************" >> "$logfile"
    
    exit 0
    

    Also edit variables you need and replace database credentials at line starting with mysqldump after it press “Esc”.

  3. Then save the file by pressing “:” (colon), then “wq” and press enter.

  4. Run it to rest that it creates backups successfully:

    /etc/cron.daily/db-backup-mydb
    

    When you open your /home/myapp/backups folder you will see sql.gz backup file and a log file with debug information about backup process.

To make weekly backups the only few things you need to change is to place the script into /etc/cron.weekly/ folder, replace filename part “daily” to “weekly” and change “-mtime +8” to “-mtime +56” to keep last 8 weekly backups.

MySql (MariaDB) crashes on small RAM VPS, what to do

Recently I encountered one weird problem, my MariaDB database started to crash from time to time on one of my small RAM (512mb) virtual private servers. After some short googling I found out what what is potential problem with MariaDB on small RAM machines and how to fix it.

First of all, if you have this kind of problem, check MariaDB logs

tail -n 100 /var/log/mariadb/mariadb.log

you may find something like this:

160608 12:08:05 InnoDB: Completed initialization of buffer pool
160608 12:08:05 InnoDB: Fatal error: cannot allocate memory for the buffer pool
160608 12:08:05 [ERROR] Plugin 'InnoDB' init function returned error.
160608 12:08:05 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
160608 12:08:05 [ERROR] mysqld: Out of memory (Needed 128917504 bytes)

After some research I figured out that mysql require a lot resources for performance schema, and disabling it will help on small memory machines. source

sudo vim /etc/my.cnf

add

performance_schema = off

to section

[mysqld]

To ensure that database server will restart on crash, on OS with Systemd like CentOS 7 you need to do following

Open following file for edit

sudo vim /etc/systemd/system/mariadb.service

and add following lines

.include /lib/systemd/system/mariadb.service

[Service]
Restart=always
RestartSec=3

Then you need to restart reload Systemd configuration

sudo systemctl daemon-reload

and restart MariaDB service

systemctl restart mariadb

To ensure that Systemd restarts service you can do following:

ps -ef|grep maria

You will see something like this

mysql    26647 26368  0 Jun12 ?        00:06:22 /usr/libexec/mysqld ....

Try to kill the process using

kill 26647

Wait 3 seconds and check if MariaDB started again

ps -ef|grep maria