<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ilham Syahid S</title>
    <description>The latest articles on DEV Community by Ilham Syahid S (@ilhamsyahids).</description>
    <link>https://dev.to/ilhamsyahids</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F390218%2F82251b1a-038b-47d9-ba5d-148cf9b278b4.jpeg</url>
      <title>DEV Community: Ilham Syahid S</title>
      <link>https://dev.to/ilhamsyahids</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ilhamsyahids"/>
    <language>en</language>
    <item>
      <title>How To Deploy Any Server Using Systemctl (Node JS as Example)</title>
      <dc:creator>Ilham Syahid S</dc:creator>
      <pubDate>Sun, 05 Dec 2021 10:41:31 +0000</pubDate>
      <link>https://dev.to/ilhamsyahids/how-to-deploy-server-node-js-using-systemctl-lbb</link>
      <guid>https://dev.to/ilhamsyahids/how-to-deploy-server-node-js-using-systemctl-lbb</guid>
      <description>&lt;p&gt;Suppose you have VM in the cloud, if you don't have you can have it free &lt;a href="https://ilhamsyahids.medium.com/lifetime-free-google-server-858bc32db037"&gt;here&lt;/a&gt;. You may wonder how to deploy your apps so that can be access online.&lt;/p&gt;

&lt;p&gt;Here's how to deploy any server using systemctl with nodejs as example.&lt;/p&gt;

&lt;p&gt;Common way to do it by using docker, but our approach right now is using &lt;strong&gt;systemctl&lt;/strong&gt;.&lt;br&gt;
&lt;strong&gt;Systemctl&lt;/strong&gt; is utility for controlling the systemd system and service manager.&lt;br&gt;
I always analogy with the process that run along with system in paralel.&lt;/p&gt;
&lt;h2&gt;
  
  
  Create Simple App
&lt;/h2&gt;

&lt;p&gt;Let's start with create simple webservice using nodejs and express.&lt;/p&gt;
&lt;h3&gt;
  
  
  Install dependencies
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Connect via SSH&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Update package Linux&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Install Node.js&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;nodejs
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Check with:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;node &lt;span class="nt"&gt;-v&lt;/span&gt;
v8.10.0
&lt;/code&gt;&lt;/pre&gt;



&lt;blockquote&gt;
&lt;p&gt;You may have different version&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Install NPM&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;npm
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Create Express App
&lt;/h3&gt;

&lt;p&gt;Quick start create express app &lt;a href="https://github.com/expressjs/express#quick-start"&gt;here&lt;/a&gt; with some modification.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install executable&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; express-generator@4
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create app&lt;/p&gt;

&lt;p&gt;Create starting app&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;express ~/foo &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; ~/foo
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install dependencies&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start server&lt;/p&gt;

&lt;p&gt;Before we start, we have to change port server &lt;code&gt;3000&lt;/code&gt; to &lt;code&gt;80&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;pico bin/www
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Search for &lt;code&gt;3000&lt;/code&gt; or go to line (&lt;code&gt;CTRL + SHIFT + _&lt;/code&gt;) 15 and change into &lt;code&gt;80&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Exit (&lt;code&gt;CTRL + X&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Run server&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;npm start
&lt;/code&gt;&lt;/pre&gt;


&lt;blockquote&gt;
&lt;p&gt;IMPORTANT: make sure it on the port &lt;code&gt;80&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your application now is running, but after you close the SSH the application will vanish and you cant access it.&lt;/p&gt;

&lt;p&gt;Now, we're moving to the next step.&lt;br&gt;
Stop the app, if it still running.&lt;/p&gt;
&lt;h2&gt;
  
  
  Create Service
&lt;/h2&gt;

&lt;p&gt;Systemctl consist of many units system.&lt;/p&gt;

&lt;p&gt;Check units with &lt;code&gt;sudo systemctl list-units&lt;/code&gt;, bunch of unit will come up.&lt;/p&gt;

&lt;p&gt;Here's the example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ilhamsyahids@instance-1:~&lt;span class="nv"&gt;$ &lt;/span&gt;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
...                              ...    ...    ...       ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create Unit
&lt;/h3&gt;

&lt;p&gt;In order to use systemctl, you have to create the unit.&lt;/p&gt;

&lt;p&gt;Suppose you are in the app directory (&lt;code&gt;/home/$USER/foo&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;Create file, let's called &lt;code&gt;foo.service&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;foo.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open file then write&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Unit]&lt;/span&gt;
&lt;span class="py"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Foo application&lt;/span&gt;

&lt;span class="nn"&gt;[Service]&lt;/span&gt;
&lt;span class="py"&gt;User&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;USER&amp;gt;&lt;/span&gt;
&lt;span class="py"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/home/&amp;lt;USER&amp;gt;/foo&lt;/span&gt;
&lt;span class="py"&gt;ExecStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/npm start&lt;/span&gt;
&lt;span class="py"&gt;Restart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;on-failure&lt;/span&gt;

&lt;span class="nn"&gt;[Install]&lt;/span&gt;
&lt;span class="py"&gt;WantedBy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Unit]&lt;/span&gt;
&lt;span class="py"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Foo application&lt;/span&gt;

&lt;span class="nn"&gt;[Service]&lt;/span&gt;
&lt;span class="py"&gt;User&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;ilhamsyahids&lt;/span&gt;
&lt;span class="py"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/home/ilhamsyahids/foo&lt;/span&gt;
&lt;span class="py"&gt;ExecStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/npm start&lt;/span&gt;
&lt;span class="py"&gt;Restart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;on-failure&lt;/span&gt;

&lt;span class="nn"&gt;[Install]&lt;/span&gt;
&lt;span class="py"&gt;WantedBy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Will quickly deep dive in the end of article&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Save and close.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run Unit
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Move unit into systemd folder&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp &lt;/span&gt;foo.service /etc/systemd/system
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reload daemon&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl daemon-reload
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Start unit&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl start foo.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check status unit&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl status foo.service
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;You'll find something like this:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ilhamsyahids@instance-1:~&lt;span class="nv"&gt;$ &lt;/span&gt;systemctl status foo.service
● foo.service - Foo application
Loaded: loaded &lt;span class="o"&gt;(&lt;/span&gt;/etc/systemd/system/foo.service&lt;span class="p"&gt;;&lt;/span&gt; disabled&lt;span class="p"&gt;;&lt;/span&gt; vendor preset: enabled&lt;span class="o"&gt;)&lt;/span&gt;
Active: active &lt;span class="o"&gt;(&lt;/span&gt;running&lt;span class="o"&gt;)&lt;/span&gt; since Fri 2021-12-03 11:28:45 UTC&lt;span class="p"&gt;;&lt;/span&gt; 5h 18min ago
Main PID: 5405 &lt;span class="o"&gt;(&lt;/span&gt;npm&lt;span class="o"&gt;)&lt;/span&gt;
    Tasks: 21 &lt;span class="o"&gt;(&lt;/span&gt;limit: 1120&lt;span class="o"&gt;)&lt;/span&gt;
CGroup: /system.slice/foo.service
        ├─5405 npm
        ├─5451 sh &lt;span class="nt"&gt;-c&lt;/span&gt; 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 - -
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Make sure your VM is open HTTP and HTTPS&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now your app will serve even when you are exit the SSH connection, your app will remains.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deep Dive
&lt;/h2&gt;

&lt;p&gt;Found article that describe structure in the unit &lt;a href="https://linuxconfig.org/how-to-create-systemd-service-unit-in-linux"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Unit]&lt;/span&gt;
&lt;span class="py"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Foo application&lt;/span&gt;

&lt;span class="nn"&gt;[Service]&lt;/span&gt;
&lt;span class="py"&gt;User&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;ilhamsyahids&lt;/span&gt;
&lt;span class="py"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/home/ilhamsyahids/foo&lt;/span&gt;
&lt;span class="py"&gt;ExecStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/npm start&lt;/span&gt;
&lt;span class="py"&gt;Restart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;on-failure&lt;/span&gt;

&lt;span class="nn"&gt;[Install]&lt;/span&gt;
&lt;span class="py"&gt;WantedBy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unit contains three section:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;[Unit]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Information about the unit.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;[Service]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Information about "what will you do"&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;[Install]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Information about where unit will served&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Focus on "what will you do":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Property &lt;code&gt;User&lt;/code&gt; optional but make as least privilege.&lt;/li&gt;
&lt;li&gt;Instead of using &lt;code&gt;cd&lt;/code&gt; to our app folder, simply using &lt;code&gt;WorkingDirectory=&amp;lt;path-app-folder&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ExecStart&lt;/code&gt; the important property for execute the app. Do not reference with alias such as  &lt;code&gt;npm start&lt;/code&gt; but point into the binary exec &lt;code&gt;/usr/bin/npm start&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Suppose you have any server you can change exec here. e.g. Ruby: &lt;code&gt;/home/user/.rbenv/shims/ruby main.rb&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Restart=on-failure&lt;/code&gt; restart the process when it crashed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Environment&lt;/code&gt; the env variable. e.g: &lt;code&gt;Environment="ENV=production"&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next Step
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Serve using reserve proxy NGINX or Caddy&lt;/li&gt;
&lt;li&gt;Deploy many app with multiple port in single VM (port forwarding)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reach Me
&lt;/h2&gt;

&lt;p&gt;Any issue? Reach me at &lt;a href="https://ilhamsyahids.com/"&gt;ilhamsyahids.com&lt;/a&gt; or &lt;em&gt;&lt;a href="mailto:me@ilhamsyahids.com"&gt;me@ilhamsyahids.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>systemctl</category>
      <category>server</category>
    </item>
  </channel>
</rss>
