How can I automatically start a node.js application in Amazon Linux AMI on aws?

Linuxnode.jsAmazon Ec2Amazon Web-Services

Linux Problem Overview


Is there a brief guide to explain how to start up a application when the instance starts up and running? If it were one of the services installed through yum then I guess I can use /sbin/chkconfig to add it to the service. (To make it sure, is it correct?)

However, I just want to run the program which was not installed through yum. To run node.js program, I will have to run script sudo node app.js at home directory whenever the system boots up.

I am not used to Amazon Linux AMI so I am having little trouble finding a 'right' way to run some script automatically on every boot.

Is there an elegant way to do this?

Linux Solutions


Solution 1 - Linux

One way is to create an upstart job. That way your app will start once Linux loads, will restart automatically if it crashes, and you can start / stop / restart it by sudo start yourapp / sudo stop yourapp / sudo restart yourapp.

Here are beginning steps:

  1. Install upstart utility (may be pre-installed if you use a standard Amazon Linux AMI):

    sudo yum install upstart

For Ubuntu:

sudo apt-get install upstart

2) Create upstart script for your node app:

in /etc/init add file yourappname.conf with the following lines of code:

#!upstart
description "your app name"

start on started mountall
stop on shutdown

# Automatically Respawn:
respawn
respawn limit 99 5

env NODE_ENV=development

# Warning: this runs node as root user, which is a security risk
# in many scenarios, but upstart-ing a process as a non-root user
# is outside the scope of this question
exec node /path_to_your_app/app.js >> /var/log/yourappname.log 2>&1

3) start your app by sudo start yourappname

Solution 2 - Linux

You can use forever-service for provisioning node script as a service and automatically starting during boots. Following commands will do the needful,

npm install -g forever-service
forever-service install test

This will provision app.js in the current directory as a service via forever. The service will automatically restart every time system is restarted. Also when stopped it will attempt a graceful stop. This script provisions the logrotate script as well.

Github url: https://github.com/zapty/forever-service

As of now forever-service supports Amazon Linux, CentOS, Redhat support for other Linux distro, Mac and Windows are in works..

NOTE: I am the author of forever-service.

Solution 3 - Linux

Quick solution for you would be to start your app from /etc/rc.local ; just add your command there.

But if you want to go the elegant way, you'll have to package your application in a rpm file, have a startup script that goes in /etc/rc.d so that you can use chkconfig on your app, then install the rpm on your instance.

Maybe this or this help. (or just google for "creating rpm packages")

Solution 4 - Linux

You can create a script that can start and stop your app and place it in /etc/init.d; make the script adhere to chkconfig's conventions (below), and then use chkconfig to set it to start when other services are started.

You can pick an existing script from /etc/init.d to use as an example; this article describes the requirements, which are basically:

  • An executable script that identifies the shell needed (i.e., #!/bin/bash)
  • A comment of the form # chkconfig: where is often 345, startprio indicates where in the order of services to start, and stopprio is where in the order of services to stop. I generally pick a similar service that already exists and use that as a guide for these values (i.e., if you have a web-related service, start at the same levels as httpd, with similar start and stop priorities).

Once your script is set up, you can use

 chkconfig --add yourscript 
 chkconfig yourscript on 

and you should be good to go. (Some distros may require you to manually symlink to the script to /etc/init.d/rc.d, but I believe your AWS distro will do that for you when you enable the script.

Solution 5 - Linux

My Amazon Linux instance runs on Ubuntu, and I used systemd to set it up.

First you need to create a <servicename>.service file. (in my case cloudyleela.service)

sudo nano /lib/systemd/system/cloudyleela.service

Type the following in this file:

[Unit]
Description=cloudy leela
Documentation=http://documentation.domain.com
After=network.target

[Service]
Type=simple
TimeoutSec=0
User=ubuntu
ExecStart=/usr/bin/node /home/ubuntu/server.js
Restart=on-failure

[Install]
WantedBy=multi-user.target

In this application the node application is started. You will need a full path here. I configured that the application should simply restart if something goes wrong. The instances that Amazon uses have no passwords for their users by default.

Reload the file from disk, and then you can start your service. You need to enable it to make it active as a service, which automatically launches at startup.

ubuntu@ip-172-31-21-195:~$ sudo systemctl daemon-reload
ubuntu@ip-172-31-21-195:~$ sudo systemctl start cloudyleela
ubuntu@ip-172-31-21-195:~$ sudo systemctl enable cloudyleela
Created symlink /etc/systemd/system/multi-user.target.wants/cloudyleela.service → /lib/systemd/system/cloudyleela.service.
ubuntu@ip-172-31-21-195:~$

A great systemd for node.js tutorial is available here.

If you run a webserver:

You probably will have some issues running your webserver on port 80. And the easiest solution, is actually to run your webserver on a different port (e.g. 4200) and then to redirect that port to port 80. You can accomplish this with the following command:

sudo iptables -t nat -A PREROUTING -i -p tcp --dport 80 -j REDIRECT --to-port 4200

Unfortunately, this is not persistent, so you have to repeat it whenever your server restarts. A better approach is to also include this command in our service script:

  1. ExecStartPre to add the port forwarding
  2. ExecStopPost to remove the port forwarding
  3. PermissionStartOnly to do this with sudo power

So, something like this:

[Service]
...
PermissionsStartOnly=true
ExecStartPre=/sbin/iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 4200
ExecStopPost=/sbin/iptables -t nat -D PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 4200

Don't forget to reload and restart your service:

[ec2-user@ip-172-31-39-212 system]$ sudo systemctl daemon-reload
[ec2-user@ip-172-31-39-212 system]$ sudo systemctl stop cloudyleela
[ec2-user@ip-172-31-39-212 system]$ sudo systemctl start cloudyleela
[ec2-user@ip-172-31-39-212 system]$

For microservices (update on Dec 2020)

The previously mentioned solution gives a lot of flexibility, but it does take some time to set it up. And for each additional application, you need to go through this entire process again. By the time you'll be installing your 5th node application, you'll certainly start wondering: "there has to be a shortcut".

The advantage of PM2 is that it's just 1 service to install. Next it's PM2 which manages the actual applications.

Even the initial setup of PM2 is easy, because it automatically installs the pm2 service for you.

npm install pm2 -g

And adding new services is even easier:

pm2 start index.js --name "foo"`. 

When everything's up and running, you can save your setup, to have it automatically start on reboot.

pm2 save

If you want an overview of all your running node applications, you can run pm2 list

And PM2 also offers an online (webbased) dashboard to monitor your application remotely. You may need a license to access some of the dashboard functionality though (which is a bit over-priced imho).

Solution 6 - Linux

Use Elastic Beanstalk :) Provides support for auto-scaling, SSL termination, blue/green deployments, etc

If you want the salty sysadmin way for a RedHat based linux distro (Amazon Linux is a flavor of RedHat), learn systemd, as mentioned by @bvdb in the answer above:

https://en.wikipedia.org/wiki/Systemd

Set everything up as described on an EC2 instance, snapshot a custom AMI, and use this custom AMI as your base for EC2 instances hosting your apps. This way you don't have to go through all that setup multiple times. You'll probably want to get acquainted with load balancers too, if you are running in a production environment with uptime requirements.

Or, yes, as mentioned by @bvdb, you could also use pm2 to interface with systemd. Though I don't think pm2 helps with running your app across multiple EC2 instances, which is definitely recommended for production environments with uptime requirements.

All of which is a very steep learning curve. Since the OP seemed to be new to all this, Elastic Beanstalk, Google App Engine, and others are a great way to get code running in the cloud without all that.

These days I dev in TypeScript, deploying to serverless function execution in the cloud for most things, and don't have to think about package installs or app startup at all.

Solution 7 - Linux

You can use screen. Run crontab -e and add this line:

@reboot  screen -d -m bash -c "cd /home/user/yourapp/; node app"

Solution 8 - Linux

Have been using forever on AWS and it does a good job. Install using

 [sudo] npm install forever -g

To add an application use

 forever start path_to_application

and to stop the application use

 forever stop path_to_application

This is a useful article that helped me with setting it up.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser482594View Question on Stackoverflow
Solution 1 - Linuxmvbl fstView Answer on Stackoverflow
Solution 2 - LinuxarvaView Answer on Stackoverflow
Solution 3 - LinuxUnknownView Answer on Stackoverflow
Solution 4 - LinuxTomGView Answer on Stackoverflow
Solution 5 - LinuxbvdbView Answer on Stackoverflow
Solution 6 - LinuxTim FulmerView Answer on Stackoverflow
Solution 7 - LinuxToolkitView Answer on Stackoverflow
Solution 8 - LinuxalmypalView Answer on Stackoverflow