Skip to content

Instantly share code, notes, and snippets.

@tg21
Last active October 31, 2020 08:13
Show Gist options
  • Save tg21/27008429280d844dd3a89f67aaef750b to your computer and use it in GitHub Desktop.
Save tg21/27008429280d844dd3a89f67aaef750b to your computer and use it in GitHub Desktop.
Setting Up MEAN stack app on amazon-ec2 with free TLS support for express and websockets as background service

Do exactly like this in this specific order

First Launch an instance (ubuntu is preferred) with port 22,80 and 443 open for ssh, http and https respectively.

after successfully ssh-ing into your server using ssh -i <ssh_key.pem> ubuntu@<your_server_ip> run following commands

Install Pre-requisites for MEAN

Install Node

go to nodesource and choose method to install latest LTS node e.g.- for Node 12 LTS run following

curl -sL https://deb.nodesource.com/setup_lts.x | sudo -E bash - 
sudo apt-get install -y nodejs

Install Mongo

Use this to install mongo properly based on distro and version.

Pull your MEAN stack app using git into /usr/local/bin

install NODE dependencies
sudo npm i
For HTTPS use following code in entry_file.js
 #!/usr/bin/env node

const express = require('express')
const app = express();
const https = require('https');
const http = require('http');
const fs = require('fs');
const port = process.env.PORT || 3000
const tlsPort = 443;
// app.get('/', function(req, res) {
//     res.sendFile(__dirname + "/web/index.html");
// });


var credentials = {};

// Certificate : uncomment below code at the end after getting free certificates using certbot

// const privateKey = fs.readFileSync('/etc/letsencrypt/live/site_name.com/privkey.pem', 'utf8');
// const certificate = fs.readFileSync('/etc/letsencrypt/live/site_name.com/cert.pem', 'utf8');
// const ca = fs.readFileSync('/etc/letsencrypt/live/site_name.com/chain.pem', 'utf8');

// credentials = {
//	 key: privateKey,
//	 cert: certificate,
//	 ca: ca
// };

//importand to allow dot files to get free TLS certificate
app.use(express.static('web/',{dotfiles: 'allow'}))
var bodyParser = require('body-parser');

app.use(express.json()); // to support JSON-encoded bodies
app.use(express.urlencoded({ // to support URL-encoded bodies
    extended: true
}));

app.get('/', (req, res) => {
    res.send('Hello There');
})

app.get('/testIfServerIsRunning', (req, res) => {
    res.send('Yes Its Running');
})


const httpsServer = https.createServer(credentials, app).listen(tlsPort, function() {
    console.log('listening Securely on ' + tlsPort);
});

//----------------WEBSOCKETS PART -------------------------//

// specify both app and server so, socket will know that https option is present
const ws = require('express-ws')(app, httpsServer);

app.ws('/', (ss, req) => {
    console.log('websocket connection');
    
    // define on('message'), on('close') functions here
});


// create http server as well and redirect all requests on https server
http.createServer(function (req, res) {
    res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url });
    res.end();
}).listen(80);

Use Certbot to get free TLS certificate for your site

Use process mentioned here no need for me to write it again

Renewing certificate after 3 months(important)

   sudo systemctl stop site
   sudo certbot renew --standalone
   sudo systemctl start site

Turning node process into a background service, so it won't crash when you end your ssh session

Make a configuration file like below at /etc/systemd/system/site.service. include path for sudo in ExecStart because port 443 and 80 are privilaged ports and require root { there are security risks with running node as root though, but as long as you know what you are doing its fine}

[Unit]
Description=Node backend for Application

StartLimitIntervalSec=500
StartLimitBurst=5

[Service]
Restart=on-failure
RestartSec=5s

ExecStart=/usr/bin/sudo /usr/bin/npm start

WorkingDirectory=/usr/local/bin/site/your_app_dir
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=site
User=ubuntu
Group=nogroup
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target

Enable the service.

sudo systemctl enable site.service
Created symlink from /etc/systemd/system/multi-user.target.wants/site.service to /etc/systemd/system/site.service.

Show service status

sudo systemctl status site

Reload service after changing

sudo systemctl daemon-reload

Restart the service

sudo systemctl restart site

Show logs

tail -f /var/log/syslog
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment