Suppose you have VM in the cloud, if you dont have you can have it free here. You may wonder how to deploy your apps so that can be access online.
Here's how to deploy any server using systemctl with nodejs as example.
Common way to do it by using docker, but our approach right now is using systemctl. Systemctl is utility for controlling the systemd system and service manager. I always analogy with the process that run along with system in paralel.
Create Simple App
Let's start with create simple webservice using nodejs and express.
Install dependencies
Connect via SSH
Update package Linux
sudo apt update
Install Node.js
sudo apt install nodejs
Check with:
$ node -v
v8.10.0You may have different version
Install NPM
sudo apt install npm
Create Express App
Quick start create express app here with some modification.
Install executable
npm install -g express-generator@4
Create app
Create starting app
express ~/foo && cd ~/foo
Install dependencies
npm install
Start server
Before we start, we have to change port server
3000
to80
.sudo pico bin/www
Search for
3000
or go to line (CTRL + SHIFT + _
) 15 and change into80
.Exit (
CTRL + X
).Run server
sudo npm start
IMPORTANT: make sure it on the port
80
Your application now is running, but after you close the SSH the application will vanish and you cant access it.
Now, we're moving to the next step. Stop the app, if it still running.
Create Service
Systemctl consist of many units system.
Check units with sudo systemctl list-units
, bunch of unit will come up.
Here's the example:
ilhamsyahids@instance-1:~$ systemctl list-units
UNIT LOAD ACTIVE SUB DESCRIPTION
... ... ... ... ...
accounts-daemon.service loaded active running Accounts Service
apparmor.service loaded active exited AppArmor initialization
apport.service loaded active exited LSB: automatic crash report generation
atd.service loaded active running Deferred execution scheduler
blk-availability.service loaded active exited Availability of block devices
chrony.service loaded active running chrony, an NTP client/server
... ... ... ... ...
Create Unit
In order to use systemctl, you have to create the unit.
Suppose you are in the app directory (/home/$USER/foo
)
Create file, let's called foo.service
touch foo.service
Open file then write
[Unit]
Description=Foo application
[Service]
User=<USER>
WorkingDirectory=/home/<USER>/foo
ExecStart=/usr/bin/npm start
Restart=on-failure
[Install]
WantedBy=multi-user.target
For example:
[Unit]
Description=Foo application
[Service]
User=ilhamsyahids
WorkingDirectory=/home/ilhamsyahids/foo
ExecStart=/usr/bin/npm start
Restart=on-failure
[Install]
WantedBy=multi-user.target
Will quickly deep dive in the end of article
Save and close.
Run Unit
Move unit into systemd folder
cp foo.service /etc/systemd/system
Reload daemon
systemctl daemon-reload
Start unit
systemctl start foo.service
Check status unit
systemctl status foo.service
You'll find something like this:
ilhamsyahids@instance-1:~$ systemctl status foo.service
โ foo.service - Foo application
Loaded: loaded (/etc/systemd/system/foo.service; disabled; vendor preset: enabled)
Active: active (running) since Fri 2021-12-03 11:28:45 UTC; 5h 18min ago
Main PID: 5405 (npm)
Tasks: 21 (limit: 1120)
CGroup: /system.slice/foo.service
โโ5405 npm
โโ5451 sh -c node ./bin/www
โโ5452 node ./bin/www
Dec 03 11:29:05 instance-1 npm[5405]: GET / 304 787.911 ms - -
Dec 03 11:29:05 instance-1 npm[5405]: GET /stylesheets/style.css 304 1.683 ms - -
Make sure your VM is open HTTP and HTTPS
Now your app will serve even when you are exit the SSH connection, your app will remain.
Deep Dive
Found article that describe structure in the unit here.
[Unit]
Description=Foo application
[Service]
User=ilhamsyahids
WorkingDirectory=/home/ilhamsyahids/foo
ExecStart=/usr/bin/npm start
Restart=on-failure
[Install]
WantedBy=multi-user.target
Unit contains three section:
[Unit]
Information about the unit.
[Service]
Information about "what will you do"
[Install]
Information about where unit will served
Focus on "what will you do":
Property
User
optional but make as least privilege.Instead of using
cd
to our app folder, simply usingWorkingDirectory=<path-app-folder>
ExecStart
the important property for execute the app. Do not reference with alias such asnpm start
but point into the binary exec/usr/bin/npm start
Suppose you have any server you can change exec here. e.g. Ruby:
/home/user/.rbenv/shims/ruby main.rb
Restart=on-failure
restart the process when it crashedEnvironment
the env variable. e.g:Environment="ENV=production"
Next Step
- Serve using reserve proxy NGINX or Caddy
- Deploy many app with multiple port in single VM (port forwarding)
Reach Me
Any issue? Reach me at [email protected]