← Back to Blog DevOps

How to Safely Configure Nginx and Systemd for Node.js Applications

Deploying a Node.js application in a production environment requires more than running node app.js in your terminal. As soon as you log out of your SSH session, the process will terminate. Furthermore, exposing your application directly on port 80 or 443 is a major security risk.

A professional DevOps setup solves these problems using two core system components:

  1. Systemd: To run your Node.js process as a background service that auto-starts on boot and recovers from crashes.
  2. Nginx: Sits as a secure reverse proxy in front of Node.js to handle SSL/TLS termination, rate limiting, and high-performance routing.

In this guide, we will walk you through setting up a bulletproof deployment structure completely locally—keeping your configurations, ports, and environment variables completely private.

1. The Systemd Service: Keep Your App Alive

Systemd is the default init system for modern Linux distributions (Ubuntu, Debian, CentOS). It manages system processes and services. To configure your application, you need to create a service file.

Rather than writing it manually, you can instantly bootstrap one in your browser using our client-side Systemd Service Generator.

Create a file under /etc/systemd/system/node-app.service with the following standard robust structure:

[Unit]
Description=Node.js Production Application
After=network.target

[Service]
Type=simple
User=nodeuser
Group=nodeuser
WorkingDirectory=/var/www/node-app
ExecStart=/usr/bin/node server.js
Restart=always
RestartSec=10
Environment=NODE_ENV=production PORT=3000
EnvironmentFile=/var/www/node-app/.env

[Install]
WantedBy=multi-user.target

Key parameters explained:

  • User=nodeuser: Avoid running your application as root. If the application is compromised, the attacker will only gain restricted user permissions.
  • Restart=always: Tells Systemd to automatically relaunch the Node.js process if it crashes due to memory leaks or unexpected exceptions.
  • EnvironmentFile: Loads your environment configuration securely. If your .env file is messy, clean it up with our Env File Formatter. If you need to convert it, try our Env to JSON Converter.

After creating the file, enable and start the service with these commands:

sudo systemctl daemon-reload
sudo systemctl enable node-app
sudo systemctl start node-app
sudo systemctl status node-app

2. Configuring Nginx: The Gatekeeper Reverse Proxy

Now that Node.js is running locally on port 3000, we need to map external web traffic (port 80 and 443) to it. Nginx acts as our reverse proxy.

You can build a production-ready server block matching this setup in seconds using our Nginx Config Generator.

Create your Nginx configuration under /etc/nginx/sites-available/yourdomain.com:

server {
    listen 80;
    listen [::]:80;
    server_name yourdomain.com www.yourdomain.com;

    # Redirect all HTTP traffic to secure HTTPS
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name yourdomain.com;

    # SSL Certs (Managed securely via Let's Encrypt Certbot)
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Enable the site block by linking it to the active folder and restarting Nginx:

sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx

3. Securing Connections and Deployments

When working with databases, secure your configuration strings carefully. Avoid putting passwords directly in code files. Instead, parse them using our Connection String Parser to extract database configurations safely into separate variables.

To automate configuring hosts and SSH profiles on your servers, generate optimized local configs using our browser-based SSH Config Generator. Keeping these config operations offline ensures no remote service ever snoops on your backend host ports or connection parameters.

Summary Table of Server Operations

Component Primary Command Configuration Path
Systemd Service sudo systemctl start node-app /etc/systemd/system/node-app.service
Nginx Config sudo systemctl restart nginx /etc/nginx/sites-available/
Let's Encrypt SSL sudo certbot --nginx -d yourdomain.com /etc/letsencrypt/

Frequently Asked Questions

Why should I use Systemd for Node.js applications?
Systemd ensures your Node.js application runs as a background service, auto-starts on system boot, automatically restarts on failure, and pipes application console logs securely into systemd journald.
What does an Nginx reverse proxy do for Node.js?
An Nginx reverse proxy sits in front of your Node.js application. It intercepts public HTTP/HTTPS traffic, handles SSL termination, manages static file caching, provides rate limiting, and forwards dynamic requests to Node.js running on a local port.
How do I secure my application environment variables?
Store environment variables in a protected file (like /etc/node-app/.env) with restricted file permissions (e.g., chmod 600) owned by the application service user, and link it via your Systemd EnvironmentFile directive.