{"componentChunkName":"component---src-templates-post-js","path":"/post/running-your-node-js-app-with-systemd-part-1","result":{"data":{"contentfulHero":{"coverImage":{"file":{"url":"//images.ctfassets.net/xmu5vdhtphau/1jqMTE2RJBiMLIcZAnu6It/5495c6ec7df10a55768df442e73fe4b2/home-hero-min.jpg","fileName":"home-hero-min.jpg"}}}},"pageContext":{"post":{"id":"8774ed71-8c13-5526-b31d-b17b4e203f63","slug":"running-your-node-js-app-with-systemd-part-1","title":"Running Your Node.js App With Systemd - Part 1","createdAt":"Jun 04, 2020","tweetText":null,"type":"blog","video":null,"podcast":null,"categories":[{"id":"50768c9e-fc69-55ce-8a68-88617e5bcfbd","name":"How To","slug":"how-to"},{"id":"4384d042-dd09-5c7b-967b-95eab1334a2c","name":"Node.js","slug":"node-js"}],"image":{"file":{"url":"//images.ctfassets.net/xmu5vdhtphau/7hMby0z6l7JP5c9uQWoz0T/b543178d4eff1f68fd23dad178eeee44/5-min.jpg","fileName":"5-min.jpg"}},"author":{"name":"NodeSource","bio":{"childMarkdownRemark":{"html":"<p>This blog post was first published in NodeSource blog. Find out more <a href=\"https://nodesource.com/blog\">here</a></p>"}},"avatar":{"file":{"fileName":"mark-circle-light-1-solid@4x.png","url":"//images.ctfassets.net/xmu5vdhtphau/6TzBUzOu342mquRuYsxWhj/27416699cd376436863f29e85851ff19/mark-circle-light-1-solid_4x.png"}}},"bodyContent":{"childMarkdownRemark":{"html":"<p>You've written the next great application, in Node, and you are ready to unleash it upon the world. Which means you can no longer run it on your laptop, you're going to actually have to put it up on some server somewhere and connect it to the real Internet. Eek.</p>\n<p>There are a lot of different ways to run an app in production. This post is going to cover the specific case of running something on a \"standard\" Linux server that uses <code>systemd</code>, which means that we are <strong>not</strong> going to be talking about using Docker, AWS Lambda, Heroku, or any other sort of managed environment. It's just going to be you, your code, and terminal with a <code>ssh</code> session my friend.</p>\n<p>Before we get started though, let's talk for just a brief minute about what <code>systemd</code> actually is and why you should care.</p>\n<h2>What is <code>systemd</code> Anyway?</h2>\n<p>The full answer to this question is big, as in, \"ginormous\" sized big. So we're not going to try and answer it fully since we want to get on the the part where we can launch our app. What you need to know is that <code>systemd</code> is a thing that runs on \"new-ish\" Linux servers that is responsible for starting / stopping / restarting programs for you. If you install <code>mysql</code>, for example, and whenever you reboot the server you find that <code>mysql</code> is already running for you, that happens because <code>systemd</code> knows to turn <code>mysql</code> on when the machine boots up.</p>\n<p>This <code>systemd</code> machinery has replaced older systems such as <code>init</code> and <code>upstart</code> on \"new-ish\" Linux systems. There is a lot of arguably justified angst in the world about exactly how <code>systemd</code> works and how intrusive it is to your system. We're not here to discuss that though. If your system is \"new-ish\", it's using <code>systemd</code>, and that's what we're all going to be working with for the forseeable future.</p>\n<p>What does \"new-ish\" mean specifically? If you are using any of the following, you are using <code>systemd</code>:</p>\n<ul>\n<li>CentOS 7 / RHEL 7</li>\n<li>Fedora 15 or newer</li>\n<li>Debian Jessie or newer</li>\n<li>Ubuntu Xenial or newer</li>\n</ul>\n<h2>Running our App Manually</h2>\n<p>I'm going to assume you have a fresh installation of <a href=\"http://releases.ubuntu.com/16.04/\">Ubuntu Xenial</a> to work with, and that you have set up a default user named <code>ubuntu</code> that has <code>sudo</code> privileges. This is what the default will be if you spin up a Xenial instance in Amazon EC2. I'm using Xenial because it is currently the newest LTS (Long Term Support) version available from Canonical. Ubuntu Yakkety is available now, and is even <em>newer</em>, but Xenial is quite up-to-date at the time of this writing and will be getting security updates for many years to come because of its LTS status.</p>\n<p>Use <code>ssh</code> with the <code>ubuntu</code> user to get into your server, and let's install Node.</p>\n<pre><code>$ sudo apt-get -y install curl\n$ curl -sL https://deb.nodesource.com/setup_6.x | sudo bash -\n$ sudo apt-get -y install nodejs\n</code></pre>\n<p>Next let's create an app and run it manually. Here's a trivial app I've written that simply echoes out the user's environment variables.</p>\n<pre><code class=\"language-javascript\">const http = require('http');\n\nconst hostname = '0.0.0.0';\nconst port = process.env.NODE_PORT || 3000;\nconst env = process.env;\n\nconst server = http.createServer((req, res) => {\n  res.statusCode = 200;\n  res.setHeader('Content-Type', 'text/plain');\n  for (var k in env) {\n    res.write(k + \": \" + env[k] + \"\\n\");\n  }\n  res.end();\n});\n\nserver.listen(port, hostname, () => {\n  console.log(\"Server running at http://\" + hostname + \":\" + port + \"/\");\n});\n</code></pre>\n<p>Using your text editor of choice (which should obviously be <a href=\"https://www.gnu.org/software/emacs/\">Emacs</a> but I suppose it's a free country if you want to use something inferior), create a file called <code>hello_env.js</code> in the user's home directory <code>/home/ubuntu</code> with the contents above. Next run it with</p>\n<pre><code>$ /usr/bin/node /home/ubuntu/hello_env.js\n</code></pre>\n<p>You should be able to go to</p>\n<pre><code>http://11.22.33.44:3000\n</code></pre>\n<p>in a web browser now, substituting <code>11.22.33.44</code> with whatever the actual IP address of your server is, and see a printout of the environment variables for the <code>ubuntu</code> user. If that is in fact what you see, great! We know the app runs, and we know the command needed to start it up. Go ahead and press <code>Ctrl-c</code> to close down the application. Now we'll move on to the <code>systemd</code> parts.</p>\n<h2>Creating a <code>systemd</code> Service File</h2>\n<p>The \"magic\" that's needed to make <code>systemd</code> start working for us is a text file called a <code>service</code> file. I say \"magic\" because for whatever reason, this seems to be the part that people block on when they are going through this process. Fortunately, it's much less difficult and scary than you might think.</p>\n<p>We will be creating a file in a \"system area\" where everything is owned by the root user, so we'll be executing a bunch of commands using <code>sudo</code>. Again, don't be nervous, it's really very straightforward.</p>\n<p>The service files for the things that <code>systemd</code> controls all live under the directory path</p>\n<pre><code>/lib/systemd/system\n</code></pre>\n<p>so we'll create a new file there. If you're using <a href=\"https://www.nano-editor.org/\">Nano</a> as your editor, open up a new file there with:</p>\n<pre><code>sudo nano /lib/systemd/system/hello_env.service\n</code></pre>\n<p>and put the following contents in it:</p>\n<pre><code>[Unit]\nDescription=hello_env.js - making your environment variables rad\nDocumentation=https://example.com\nAfter=network.target\n\n[Service]\nEnvironment=NODE_PORT=3001\nType=simple\nUser=ubuntu\nExecStart=/usr/bin/node /home/ubuntu/hello_env.js\nRestart=on-failure\n\n[Install]\nWantedBy=multi-user.target\n</code></pre>\n<p>Let's go ahead and talk about what's in that file. In the <code>[Unit]</code> section, the <code>Description</code> and <code>Documentation</code> variables are obvious. What's less obvious is the part that says</p>\n<pre><code>After=network.target\n</code></pre>\n<p>That tells <code>systemd</code> that if it's supposed to start our app when the machine boots up, it should wait until after the main networking functionality of the server is online to do so. This is what we want, since our app can't bind to <code>NODE_PORT</code> until the network is up and running.</p>\n<p>Moving on to the <code>[Service]</code> section we find the meat of today's project. We can specify environment variables here, so I've gone ahead and put in:</p>\n<pre><code>Environment=NODE_PORT=3001\n</code></pre>\n<p>so our app, when it starts, will be listening on port 3001. This is different than the default 3000 that we saw when we launched the app by hand. You can specify the <code>Environment</code> directive multiple times if you need multiple environment variables. Next is</p>\n<pre><code>Type=simple\n</code></pre>\n<p>which tells <code>systemd</code> how our app launches itself. Specifically, it lets <code>systemd</code> know that the app won't try and fork itself to drop user privileges or anything like that. It's just going to start up and run. After that we see</p>\n<pre><code>User=ubuntu\n</code></pre>\n<p>which tells <code>systemd</code> that our app should be run as the unprivileged <code>ubuntu</code> user. You definitely want to run your apps as unprivileged users to that attackers can't aim at something running as the <code>root</code> user.</p>\n<p>The last two parts here are maybe the most interesting to us</p>\n<pre><code>ExecStart=/usr/bin/node /home/ubuntu/hello_env.js\nRestart=on-failure\n</code></pre>\n<p>First, <code>ExecStart</code> tells <code>systemd</code> what command it should run to launch our app. Then, <code>Restart</code> tells <code>systemd</code> under what conditions it should restart the app if it sees that it has died. The <code>on-failure</code> value is likely what you will want. Using this, the app will <em>NOT</em> restart if it goes away \"cleanly\". Going away \"cleanly\" means that it either exits by itself with an exit value of <code>0</code>, or it gets killed with a \"clean\" signal, such as the default signal sent by the <code>kill</code> command. Basically, if our app goes away because we want it to, then <code>systemd</code> will leave it turned off. However, if it goes away for any other reason (an unhandled exception crashes the app, for example), then <code>systemd</code> will immediately restart it for us. If you want it to restart no matter what, change the value from <code>on-failure</code> to <code>always</code>.</p>\n<p>Last is the <code>[Install]</code> stanza. We're going to gloss over this part as it's not very interesting. It tells <code>systemd</code> how to handle things if we want to start our app on boot, and you will probably want to use the values shown for most things until you are a more advanced <code>systemd</code> user.</p>\n<h2>Using <code>systemctl</code> To Control Our App</h2>\n<p>The hard part is done! We will now learn how to use the system provided tools to control our app. To being with, enter the command</p>\n<pre><code>$ sudo systemctl daemon-reload\n</code></pre>\n<p>You have to do this whenever <strong>any</strong> of the service files change <strong>at all</strong> so that <code>systemd</code> picks up the new info.</p>\n<p>Next, let's launch our app with</p>\n<pre><code>$ sudo systemctl start hello_env\n</code></pre>\n<p>After you do this, you should be able to go to</p>\n<pre><code>http://11.22.33.44:3001\n</code></pre>\n<p>in your web browser and see the output. If it's there, congratulations, you've launched your app using <code>systemd</code>! If the output looks very different than it did when you launched the app manually don't worry, that's normal. When <code>systemd</code> kicks off an application, it does so from a <em>much more minimal environment</em> than the one you have when you <code>ssh</code> into a machine. In particular, the <code>$HOME</code> environment variable may not be set by default, so be sure to pay attention to this if your app makes use of any environment variables. You may need to set them yourself when using <code>systemd</code>.</p>\n<p>You may be interested in what state <code>systemd</code> thinks the app is in, and if so, you can find out with</p>\n<pre><code>$ sudo systemctl status hello_env\n</code></pre>\n<p>Now, if you want to stop your app, the command is simply</p>\n<pre><code>$ sudo systemctl stop hello_env\n</code></pre>\n<p>and unsurprisingly, the following will restart things for us</p>\n<pre><code>$ sudo systemctl restart hello_env\n</code></pre>\n<p>If you want to make the application start up when the machine boots, you accomplish that by <em>enabling</em> it</p>\n<pre><code>$ sudo systemtl enable hello_env\n</code></pre>\n<p>and finally, if you previously enabled the app, but you change your mind and want to stop it from coming up when the machine starts, you correspondingly <em>disable</em> it</p>\n<pre><code>$ sudo systemctl disable hello_env\n</code></pre>\n<h2>Wrapping Up</h2>\n<p>That concludes today's exercise. There is much, much more to learn and know about <code>systemd</code>, but this should help get you started with some basics. In a follow up blog post, we will learn how to launch multiple instances of our app, and load balance those behind <a href=\"https://nginx.org\">Nginx</a> to illustrate a more production ready example.</p>\n<hr>\n<p>This article was first published <a href=\"https://nodesource.com/blog/running-your-node-js-app-with-systemd-part-1/\">NodeSource blog post</a> in November 2016</p>"}}}}}}