Halloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PCHalloween DealsAmazon USOctober picks are moving - compare before checkoutAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk11 min

How to Deploy Node.js Apps with systemd and Nginx

Run Node.js as a dedicated systemd service, keep it on a private loopback port, and use Nginx for public HTTP, HTTPS, WebSocket proxying, and optional load balancing.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Deploy a Node.js app as a dedicated systemd service, bind it to a private loopback port, and let Nginx handle public HTTP, HTTPS, routing, and WebSocket proxying. This arrangement starts the app at boot, restarts it after failures, centralizes logs in the journal, keeps the Node listener off the public network, and gives you one place to manage TLS.

How the deployment fits together

A production installation has three cooperating parts:

As an Amazon Associate I earn from qualifying purchases.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Node.js: your application process listens on a local port such as 127.0.0.1:3000.
  • systemd: the operating system service manager starts Node at boot, tracks its process, applies restart behavior, and records stdout and stderr in the journal.
  • Nginx: the public edge server accepts connections on ports 80 and 443, terminates TLS, adds forwarding headers, and proxies requests to Node.

Users therefore connect to your domain and Nginx, not directly to Node. Keeping Node on loopback prevents clients from bypassing Nginx’s TLS and routing rules. If Nginx is not the only entry point (for example, another proxy or a private network is involved), choose the bind address and firewall policy deliberately instead of exposing the application by default.

Prepare the host and application

Confirm the runtime and operating-system prerequisites

Use a supported Linux distribution with systemd and install the Node.js version required by the application. Verify the runtime as the same user that will run the service:

#1 Best Overall
Sale
TOZO A1 Wireless Earbuds Bluetooth 5.3 Light Weight in Ear Headphones | IPX5 Waterproof,2 Mics for AI Calls,Immersive Premium Sound Bass Headset with Charging Case,32 EQ via App Black
  • [Ultra-Lightweight Ear Buds Designed for Small Ears] Each earbud weighs only 3.7g and features a compact, ergonomic in-ear design made especially for small ears. Secure, low-profile, and comfortable for workouts, all-day wear or overnight sleeping.The ultra-slim profile sits flush in your ear with no hard edges poking or rubbing, so you can even sleep on your side without discomfort.
  • [Immersive Stereo Sound with TOZO OrigX Technology] TOZO OrigX tuning delivers clear vocals, balanced mids, and natural stereo sound for music, podcasts, and videos.
  • [Long Battery Life for Daily Use] Get up to 7 hours of playtime on a single charge, with up to 32 hours total using the charging case—ideal for workdays, commuting, and extended listening sessions.
  • [Bluetooth 5.3 & Stable Connection] Bluetooth 5.3 provides fast pairing, stable wireless performance, and reduced dropouts as you move around home or office.
  • [Deep Bass with Clear Vocals] High-performance drivers produce punchy bass while keeping vocals clean and detailed for everyday listening.
node --version
npm --version
systemctl --version

Install Nginx from your distribution’s supported package source or from an approved package repository. The exact package command and configuration-directory layout vary by distribution, so use the paths supplied by that distribution.

Create a non-root service identity

Do not run the application as root. Create a dedicated account and group, with no interactive administration privileges, then give it ownership of only the application files and directories it must write.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
sudo useradd --system --home /srv/myapp --shell /usr/sbin/nologin myapp
sudo install --directory --owner=myapp --group=myapp /srv/myapp

If your distribution uses a different system-account command or shell path, use its equivalent. Keep deployment files, uploads, logs, and secrets in separate directories when that makes permissions easier to audit.

Deploy a stable application directory

Place the release in a path that will not change between reboots, such as /srv/myapp/current, or use a versioned-release layout with a stable current link. Install production dependencies and verify the app’s start command before involving Nginx.

sudo -u myapp npm ci --omit=dev
sudo -u myapp node /srv/myapp/current/server.js

Adapt the entry point and dependency command to the project. The application should read its port from an environment variable where practical and listen on loopback:

HOST=127.0.0.1 PORT=3000 node /srv/myapp/current/server.js

Before creating the service, test the local endpoint from the server itself:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
Sale
Smart Watch for Men Women Compatible with iPhone Samsung Android Phone 1.69 inch Full Touch Screen IP68 Waterproof Bluetooh Fitness Tracker Heart Rate/Sleep Monitor (Black)
  • 【IP68 Waterproof Multifunctinal Smart Watch】Torjalph fitness activity tracker smart watch is IP68 waterproof technology ,you can wear it when swimming,handwashing,it's rain-proof which means that you perform multiple exercise modes outside without worrying about sweat or rain corroding your fitness smart watch,and this watch equipped with a 230 mAh large capacity battery magnetic charging ,and this sports activity tracker watch can be used 5-7 days If fully charged.
  • 【Larger 1.83'' Full Screen Watch & Multi-dial Selection】1.83 inch full HD color touch screen smart watch for men / women provides excellent 240*284 resolution image quality ,This Bluetooth smart watch offers a better touch experience and remarkable immersion and ,more than 200 watch faces for you to choose from App"Da Fit ", you can change the dial style according to your mood to wear keeping the world on your wrist
  • 【Accurate Activity Tracker Smart Watch 】sports watch activity tracker uses sweat and dust resistant breathable silicone strap, our Fitness Tracker Smart Watch for Android iOS Phones supports 12 sports modes,walking,running,bicycle,swimming,badminton,basketball,football,rope skipping. This bluetooth calls smart watch for men women is lightweight and stylish, bringing more convenient and relaxing sports experience while also providing more protection.
  • 【Your 24 Hour Personal Daily Health Monitor】Fitness watch for women men full touch screen IP67 waterproof bluetooth smartwatch for Android iOS Phones with heart rate blood pressure monitor multifunction Andriod smart watch with steps counter sleep monitor sports fitness watch, monitoring blood oxygen saturation allows you to understand your physical condition in real time to track fitness progress ,to know your health status in time.
  • 【More Functions Bluetooth Call Smart Watch】This fitness activity smart watch full screen for iPhone and Android phones includes a bunch of new features including:The bluetooth smart watch can hang up the phone, receive and display WhatsAPP /Text /Facebook /Twitter /Messenger reminder.Support sedentary reminder, alarm clock, stopwatch, timer,weather information,music control, remote camera control compatible with Android 5.0 and above or iOS 9.0 and above smartphones.
curl --fail http://127.0.0.1:3000/

A successful local response proves that the runtime, files, dependencies, and bind address are working independently of Nginx.

Create a systemd unit for Node.js

Write the service file

Create /etc/systemd/system/myapp.service. Use an absolute path for both Node and the application entry point. A shell-specific command such as node may work in your terminal but fail under systemd because systemd does not load your interactive shell profile.

[Unit]
Description=My Node.js application
After=network.target

[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/srv/myapp/current
Environment=NODE_ENV=production
Environment=PORT=3000
Environment=HOST=127.0.0.1
# Use the path returned by: command -v node
ExecStart=/usr/bin/node /srv/myapp/current/server.js
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Replace /usr/bin/node with the actual absolute executable path. If Node was installed with a version manager, point ExecStart at that installation’s binary and ensure the service account can traverse every parent directory. A system-wide Node installation is often simpler for a server service.

Put configuration in an environment file when needed

Environment variables can be declared in the unit, but credentials and a larger configuration set are easier to manage in a root-readable environment file:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
[Service]
EnvironmentFile=/etc/myapp/myapp.env
sudo install --directory --mode=0750 --owner=root --group=myapp /etc/myapp
sudo sh -c 'umask 027; cat > /etc/myapp/myapp.env' <<'EOF'
NODE_ENV=production
PORT=3000
HOST=127.0.0.1
# DATABASE_URL=...
EOF
sudo chown root:myapp /etc/myapp/myapp.env
sudo chmod 0640 /etc/myapp/myapp.env

Do not place secrets in a world-readable file or in a unit that is copied into public documentation. Confirm that the application understands the variable names you provide; systemd does not transform them into application-specific settings.

Load, enable, and inspect the service

After every unit-file change, reload systemd’s configuration, then enable the service for boot and start it immediately:

Rank #3
New Bee Guitar Cable 10ft Electric Instrument Bass AMP Cord
  • [Low Noise High Fidelity] New bee guitar cord with 22AWG oxygen-free-copper center conductors provides enhanced signal transfer, the PVC insulation material and the high-density stranded copper double shield provide noise rejection for quiet operation
  • [Ideal for Choice] New bee 1/4 straight and right angle metal connectors, ensures a secure connection in any instrument, pedal, or amp jack. L shape great fro on stage guitar stands
  • [Wide Compatible] Suitable for mixer, power amplifier, microphone, effector, decoder, equalizer, electoronic organ, electric guitar, electric bass and other electronic equipments. Widely used in the installation of smart home, karaoke speaker, professional stage audio, etc
  • [Easy Disassemble] Making incidental repairs quick and easy! Very nice, flexible cable
  • [Dont Hesite to Order] 24 hours customer services and professional technology team are standing by
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service
sudo systemctl status myapp.service
sudo journalctl -u myapp.service

enable --now creates the boot-time link and starts the process in one operation. Use journalctl -u myapp.service -f to follow live output while testing. A failed start normally means an incorrect executable path, missing permissions, a wrong working directory, an unavailable environment variable, or an application that exits during startup.

Configure Nginx as the reverse proxy

Define the Node upstream and virtual host

Create a server configuration in the location used by your distribution. The upstream gives the backend a name; the server block maps your hostname to it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
upstream node_backend {
    server 127.0.0.1:3000;
}

server {
    listen 80;
    server_name example.com www.example.com;

    location / {
        proxy_pass http://node_backend;
        proxy_set_header Host $host;
        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;
    }
}

Replace the hostnames and port with your values. The forwarding headers preserve the original host, client address, proxy chain, and protocol so the application can construct correct URLs and log the originating request. Make sure the Node framework is configured to trust the appropriate proxy headers; trusting every proxy indiscriminately can make client-IP and HTTPS detection unsafe.

Check DNS and network exposure

Your domain’s DNS records must point to the server that runs Nginx. Permit inbound TCP ports 80 and 443 in the host firewall and cloud firewall. The Node port should not be opened publicly when Nginx is the sole entry point. Test from the server first, then from an external network after DNS has propagated.

Validate and reload safely

Always test syntax before applying a changed configuration:

sudo nginx -t
sudo nginx -s reload

Only reload after nginx -t reports valid syntax. If your distribution provides a service wrapper, sudo service nginx reload is an equivalent reload method. A failed syntax test leaves the running configuration in place, allowing you to correct the new file without interrupting existing traffic.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
BSIMB 15.6" Digital Family Calendar & Chore Chart, No Subscription Fees
  • Digital Family Calendar: BSIMB digital calendar wall touch screen puts an end to your chaotic life. Designed for busy families, the digital calendar keeps you organised and in step with your family. Assign different colours and tasks to each family member to make family scheduling easier and more intuitive.
  • Easy Setup and Auto-Sync: Plug in, connect to WLAN and auto-syn your electric calendar in minutes. Digital wall calendar compatible with Google calendar, iCloud calendar, Outlook calendar, Cozi calendar and Yahoo calendar. Add events directly on the device or through the ecalendar app. Electronic calendar stays current whether you're at work or traveling—no manual updates needed.
  • All-In-One Home Assistant: Smart calendar builds habits and encourage independence with personalised chores. Display daily meal plan to reduce the daily ‘What's for dinner?’ stress. To-do lists keep track of everything you want. Turning chores into valuable achievements with stars and rewards, making life easier and more enjoyable.
  • Manage Anytime Anywhere: BSIMB electronic calendar for family stay connected with the powerful ecalendar app. Access and manage your digital wall calendar anytime, anywhere with free features like stars & rewards, photo screensaver, chore charts, meals plans, to-do lists etc. Electronic planner paid features like Magic Import tailor advanced tools for users with special needs.
  • Stay in Touch with Loved Ones: Share photos or videos from your phone to electronic wall calendar with app, instantly update your life moment, and keep in touch with your family, especially those who are far away; you can also surprise your smart calendar digital wall by sending him a wish card; it's also great for keeping tech-illiterate elders in touch with the youngsters.

Enable HTTPS and redirect HTTP

Configure the TLS server block

You need a certificate and matching private key issued or managed by a certificate authority or certificate service of your choice. Store the private key with restrictive permissions and reference the actual paths in Nginx:

server {
    listen 443 ssl;
    server_name example.com www.example.com;

    ssl_certificate /etc/ssl/myapp/fullchain.pem;
    ssl_certificate_key /etc/ssl/myapp/privkey.pem;

    location / {
        proxy_pass http://node_backend;
        proxy_set_header Host $host;
        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;
    }
}

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

The certificate file normally contains the server certificate and its intermediate chain, while the key file contains the corresponding private key. Do not guess filenames: confirm that both paths exist, that Nginx can read them, and that the certificate covers every hostname listed in server_name. Renewals require replacing or renewing those files and then testing and reloading Nginx.

The HTTP block performs a permanent redirect, so clients use HTTPS for subsequent requests. Keep port 80 reachable when you need HTTP-to-HTTPS redirects or certificate-validation workflows.

Proxy WebSockets correctly

WebSocket handshakes begin as HTTP but then switch protocols. The Upgrade and Connection headers are hop-by-hop headers, so Nginx must forward them explicitly in the location that handles the WebSocket endpoint.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
location /socket.io/ {
    proxy_pass http://node_backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    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;
}

Change /socket.io/ to the path used by your application. Keep ordinary HTTP requests in their normal location block. If a WebSocket client connects but immediately falls back or disconnects, inspect the Nginx error log, confirm that the backend path matches exactly, and verify that the Node process is listening on the expected port.

Run, update, and stop the service operationally

Useful systemd commands

Task Command Purpose
Start sudo systemctl start myapp.service Start without changing boot enablement.
Stop sudo systemctl stop myapp.service Stop the managed process.
Restart sudo systemctl restart myapp.service Stop and start after a release or environment change.
Boot enablement sudo systemctl is-enabled myapp.service Check whether it will start during boot.
Recent logs sudo journalctl -u myapp.service -n 100 --no-pager Read the latest service messages.
Live logs sudo journalctl -u myapp.service -f Follow startup and request-related output.

Deploy a new release

  1. Copy the new release into a separate directory rather than overwriting the running files.
  2. Install production dependencies as the service account and verify ownership and permissions.
  3. Run a local smoke test against the release’s configured port, or temporarily point a staging service at it.
  4. Update the stable current link or the service’s WorkingDirectory.
  5. Run sudo systemctl restart myapp.service, then inspect systemctl status and the journal.
  6. Run curl --fail http://127.0.0.1:3000/ and an HTTPS request through Nginx.
  7. If the release fails, point current back to the previous directory and restart the service.

Keep the previous release until the new process has passed health checks. This makes rollback a filesystem change plus a service restart instead of an emergency reconstruction.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Make Node shut down gracefully

systemd can stop a process, but the application should handle POSIX signals such as SIGTERM and SIGINT. A shutdown handler should stop accepting new work, close the HTTP server, finish or cancel background tasks, close database connections, and exit with an appropriate status.

const http = require('node:http');
const app = require('./app');

const server = http.createServer(app);
const port = Number(process.env.PORT || 3000);
const host = process.env.HOST || '127.0.0.1';

server.listen(port, host, () => {
  console.log(`Listening on ${host}:${port}`);
});

let shuttingDown = false;
async function shutdown(signal) {
  if (shuttingDown) return;
  shuttingDown = true;
  console.log(`${signal} received; closing server`);
  server.close(async () => {
    // Close databases, queues, and other resources here.
    process.exit(0);
  });
  setTimeout(() => process.exit(1), 30000).unref();
}

process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));

Do not try to recover from an uncaught exception by continuing in the same process. An uncaught exception can leave application state undefined. Let the process exit and allow systemd’s external restart policy to start a clean instance; investigate the original stack trace in the journal.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Troubleshoot in the right order

Symptom Checks and corrective action
Service fails immediately Run systemctl status myapp.service and journalctl -u myapp.service. Verify the absolute Node path, entry-point path, WorkingDirectory, file ownership, and required environment variables.
Service is active but no response locally Use ss -ltnp to confirm the expected listener, then curl http://127.0.0.1:3000/. Check that the app did not bind a different port or only an inaccessible address.
Nginx returns 502 Bad Gateway Test the backend directly with curl, confirm the upstream address and port, and read the Nginx error log. Restarting Nginx cannot fix a stopped or misbound Node process.
Domain does not reach Nginx Check DNS records, the server’s public address, and firewall rules for ports 80 and 443. Confirm that the requested hostname matches the intended server_name.
HTTPS fails to load Run nginx -t, verify certificate and key paths and permissions, confirm the certificate covers the hostname, and inspect Nginx’s TLS error output.
HTTP works but HTTPS redirects incorrectly Check the port-80 redirect, the TLS server’s server_name, and X-Forwarded-Proto. Ensure the application understands that the original request was HTTPS.
WebSocket handshake fails Use a dedicated WebSocket location with HTTP/1.1 and explicit Upgrade and Connection headers. Confirm the endpoint path and backend support.
Works in a shell but not after reboot Check systemctl is-enabled myapp.service, use absolute executable paths, avoid shell-profile-only variables, and review the boot-time journal.

When debugging a request, move from inside out: first the Node process and local curl, then Nginx configuration and logs, then DNS, firewall, and certificate state. This isolates application failures from proxy and network failures.

Scale beyond one Node.js instance

For one instance, proxy directly to its local port. For multiple instances, list each listener in an Nginx upstream group and keep the same proxy headers:

upstream node_backend {
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
}

server {
    listen 443 ssl;
    server_name example.com;
    ssl_certificate /etc/ssl/myapp/fullchain.pem;
    ssl_certificate_key /etc/ssl/myapp/privkey.pem;

    location / {
        proxy_pass http://node_backend;
        proxy_set_header Host $host;
        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;
    }
}

Nginx Open Source uses round-robin distribution by default. Before adding instances, decide how the application handles shared state, uploads, background jobs, and sessions. In-memory sessions can send a user to a different process on the next request; use a shared session store or another deliberate persistence strategy. WebSocket clients also need a consistent connection strategy because an established socket remains attached to one backend.

NGINX Plus provides additional capabilities such as advanced health checks, monitoring, session persistence, and dynamic upstream reconfiguration. Choose it only when those operational features and commercial support justify the added complexity; a small deployment can remain with one systemd service and a direct upstream.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Security and maintenance checklist

  • Run Node under a dedicated non-root account.
  • Keep the application listener on 127.0.0.1 unless a documented private-network design requires another bind address.
  • Allow inbound ports 80 and 443 only as required; do not expose the Node port publicly.
  • Restrict environment files and TLS private keys to the users and groups that need them.
  • Use absolute executable and configuration paths in systemd.
  • Use Restart=on-failure and inspect the journal after repeated restarts instead of hiding a crash loop.
  • Run nginx -t before every reload.
  • Renew certificates before expiration and reload Nginx only after validating the renewed files.
  • Test local HTTP, public HTTPS, and any WebSocket endpoint after each deployment.
  • Keep a known-good previous release for rollback.

Final deployment checklist

  1. The application starts manually with the intended production environment.
  2. The service unit has the correct user, group, working directory, absolute ExecStart, environment, and restart policy.
  3. systemctl daemon-reload has been run after unit changes.
  4. systemctl enable --now myapp.service succeeds and the journal shows a healthy process.
  5. Local curl reaches the loopback listener.
  6. Nginx’s upstream and server_name match the application and DNS name.
  7. nginx -t passes before reload.
  8. Port 80 redirects to HTTPS and the certificate and key paths are readable by Nginx.
  9. WebSocket locations include HTTP/1.1 and explicit upgrade headers when the app needs them.
  10. A reboot test confirms that systemd starts the app and Nginx can proxy it afterward.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.