Introduction
Duringinstallation of any web application to a Droplet, it’s quite alluring to simply utilize the similar setup as was used during i.e. running “node server.js” in a terminal or “ruby app.rb” to start the server. This is not only easy and simple, but it also provides visible logs. One can also utilize“nohup” or “tmux” or “screen” for keeping it running even in case of SSH session being dropped. But it’s risky: if server crashes and there is no one to restart it what will happen?
Crontab and forever can be utilized to handle this. This guide provides a powerful although a bit complex solution. Systemd (accessible on Fedora andArch, and CentOS in the future) can be utilized for managing web applications completely: uptime, logs, advanced daemon startup, resources and security through cgroupscan be all controlled, accessed and tweaked in a unified way.
This guide utilizes an easy Node.js application,however it is applicable to almost allothers as well, like Python, Ruby etc. For web applications of PHP, it is suggested to utilize a more specific LEMP or LAMP stack instead.
In this guide, commands will be given for both Arch and Fedora, be careful and keep a tab on various commands for avoiding confusion or misconfiguration. Unless otherwise indicated, same command can be used for both the systems. Additionally, it is suggested that you go through the complete tutorial first prior to pursuing it step-by-step, as this will help you in taking an overview as to what it contains and if it is suitable for your situation or not.
System Preliminaries
By default, a server with Fedora droplets and systemd. Arch Linux are configured, howeversystemd can also be deployed on different distributions as well. For this, you need to refer to your documentation: Ubuntu, Debian.
- Nginx, to be utilized as a reverse-proxy http and websocket server.
- Git, to deploy nvm, and for pulling your application in casegit is used.
- Root access. You can login as a regular user and sudo all commands, or to su – or sudosu – to a root prompt.
Installation of packages
Arch:
# pacman -Sy
# pacman -S nginx git
Fedora:
# yum install nginx git
Application Preliminaries
You can customize these settings as per your liking; however they need to be set and approved before starting.
User
An individual user account will be used by the application to run. You can decide on any name for it, but it should be easy to maintain, remember and must relate to the application. Here srv-node-sample
is utilized.
# useradd -mrU srv-node-sample
Port
In order to prevent conflicts, select a high port. We will use “15301” here.
Application Setup
Begin by deploying whatever is essential for running of the application. For Node.js (and Python, Ruby etc.), two options are there: a user-specific deployment (e.g. using nvm, rbenv, RVM, virtualenv, etc) or using the runtime of the system.
Using the system node
Arch:
# pacman -S nodejs
Fedora:
# yum install nodejs
Using a user-specific install
This needs to be deployed in the home directory of the application, i.e. /home/srv-node-sample
, and it can be done by easily logging in as that user:
# su srv-node-sample
$ cd
$ curl https://raw.github.com/creationix/nvm/master/install.sh | sh
$ source ~/.nvm/nvm.sh
$ nvm install 0.10
$ nvm alias default 0.10
Now take note as to where the node binary is deployed:
$ which node
/home/srv-node-sample/.nvm/v0.10.22/bin/node
Deploying your application
Install your code while being logged in to srv-node-sample.
Given below is only an example and your process may vary.
$ git clone [email protected]:user/repo.git .
$ npm install
$ grunt deploy
The sample application given below has been utilized for this guide:
var http = require('http');
http.createServer(function(req, res) {
res.end('<h1>Hello, world.</h1>');
}).listen(15301);
Now return to root:
$ exit
Nginx Setup
This guide only covers the essential configuration in brief. For a comprehensive guide on Nginx configuration, see the nginx manual.
Put the commands below in your server block:
location / {
proxy_pass http://localhost:15301/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Now establish its daemon:
# systemctl enable nginx
# systemctl restart nginx
Systemd Setup
—
For the application, a service file needs to be created in /etc/systemd/system/node-sample.service
.
- Also, a few variables need to be inserted:
[node binary] This is the output of “which node” as the srv-node-sample user. Either
/usr/bin/node
or the~/.nvm/...
path noted above. -
[main file] This is the major file of your application. Here, ‘index.js`.
-
Also ensure replacing
srv-node-sample
!
[Service]
ExecStart=[node binary] /home/srv-node-sample/[main file]
Restart=always
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=node-sample
User=srv-node-sample
Group=srv-node-sample
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target
Now begin the service:
# systemctl enable node-sample
# systemctl start node-sample
Usage
—
Status
—
~~~~
systemctl status node-sample
node-sample.service
Loaded: loaded (/etc/systemd/system/node-sample.service; enabled)
Active: active (running) since Fri 2013-11-22 01:12:15 UTC; 35s ago Main PID: 7213 (node) CGroup: name=systemd:/system/node-sample.service └─7213 /home/srv-node-sample/.nvm/v0.10.22/bin/node /home/srv-nod…
Nov 22 01:12:15 d02 systemd[1]: Started node-sample.service.
~~~~
Logs
—
~~~~
journalctl -u node-sample
— Logs begin at Thu 2013-11-21 19:05:17 UTC, end at Fri 2013-11-22 01:12:15 UTC. —
Nov 22 01:12:15 d02 systemd[1]: Starting node-sample.service…
Nov 22 01:12:15 d02 systemd[1]: Started node-sample.service. Nov 22 01:12:30 d02 node-sample[7213]: Sample message from application ~~~~
Restart, stop, etc
—
Force a restart:
# systemctl restart node-sample
Stop the application:
# systemctl stop node-sample
If the application is killed or if it dies, then it will automatically restart:
# systemctl status node-sample
node-sample.service
Loaded: loaded (/etc/systemd/system/node-sample.service; enabled)
Active: active (running) since Fri 2013-11-22 01:12:15 UTC; 35s ago
Main PID: 7213 (node)
CGroup: name=systemd:/system/node-sample.service
└─7213 /home/srv-node-sample/.nvm/v0.10.22/bin/node /home/srv-nod...
Nov 22 01:12:15 d02 systemd[1]: Started node-sample.service.
# kill 7213
# systemctl status node-sample
node-sample.service
Loaded: loaded (/etc/systemd/system/node-sample.service; enabled)
Active: active (running) since Fri 2013-11-22 01:54:37 UTC; 6s ago
Main PID: 7236 (node)
CGroup: name=systemd:/system/node-sample.service
└─7236 /home/srv-node-sample/.nvm/v0.10.22/bin/node /home/srv-nod...
Nov 22 01:54:37 d02 systemd[1]: node-sample.service holdoff time over, sch...t.
Nov 22 01:54:37 d02 systemd[1]: Stopping node-sample.service...
Nov 22 01:54:37 d02 systemd[1]: Starting node-sample.service...
Nov 22 01:54:37 d02 systemd[1]: Started node-sample.service.
There is a change in PID, whichactually shows that the application hasbeen killed and restarted.
Websockets
In case the application is usingwebsockets, then the lines given below need to be added to the Nginx configuration:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
and Nginx needs to be reloaded:
# systemctl reload nginx