Node.js Express Service
Create a production-ready systemd service for a Node.js Express application. Covers environment variables, working directory, logging to journal, and proper process management.
Detailed Explanation
Running Node.js in Production with systemd
Node.js applications are an ideal fit for Type=simple because Node runs in the foreground by default. A well-configured systemd unit replaces process managers like PM2 while providing better integration with the Linux system.
[Unit]
Description=Node.js Express API
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/node /opt/myapp/server.js
Restart=on-failure
RestartSec=5
User=nodeapp
Group=nodeapp
WorkingDirectory=/opt/myapp
Environment="NODE_ENV=production"
Environment="PORT=3000"
StandardOutput=journal
StandardError=journal
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
Environment Configuration
For Node.js applications, environment variables are the standard configuration method. You have two options:
Inline variables (for non-sensitive values):
Environment="NODE_ENV=production"
Environment="PORT=3000"
Environment="LOG_LEVEL=info"
Environment file (for secrets and many variables):
EnvironmentFile=/opt/myapp/.env
File Descriptor Limits
Node.js applications handling many concurrent connections need elevated file descriptor limits. The default Linux limit (1024) is too low for production servers:
LimitNOFILE=65535
This allows up to 65,535 open file descriptors (sockets, files, pipes).
Logging Integration
Setting StandardOutput=journal and StandardError=journal routes all console.log() and console.error() output to the systemd journal. You can then view logs with:
journalctl -u myapp.service -f # Follow live logs
journalctl -u myapp.service --since today # Today's logs
journalctl -u myapp.service -p err # Only errors
Why Not PM2?
While PM2 is popular in the Node.js ecosystem, systemd provides:
- Unified management: Same interface as all other system services
- Boot integration: Automatic start on system boot
- Journal logging: Centralized logging with rotation
- Resource controls: Memory/CPU limits via cgroups
- Dependency ordering: Start after databases, network, etc.
Health Checks
For Express applications, consider adding a health check endpoint and using ExecStartPost= to verify the application started correctly:
ExecStartPost=/usr/bin/curl -sf http://localhost:3000/health || exit 1
Use Case
Deploying a Node.js Express API server in production that needs automatic restart on crash, environment-based configuration, centralized logging, and integration with the system boot process.