Run an application
Create a service and reverse proxy
Run the application with systemd and let Nginx handle public HTTP and HTTPS while forwarding to the private local port.
8 minute lesson
Systemd should own the application process. It starts the app after boot, records output in the journal, applies the service user, and restarts unexpected failures.
Create /etc/systemd/system/notes-app.service:
[Unit]
Description=Notes application
After=network.target
[Service]
Type=simple
User=notes-app
Group=notes-app
WorkingDirectory=/srv/notes-app/current
EnvironmentFile=/etc/notes-app.env
ExecStart=/usr/bin/node server.js
Restart=on-failure
RestartSec=5s
TimeoutStopSec=30s
[Install]
WantedBy=multi-user.target
Use the real absolute runtime path from command -v node and the application’s real entry file. A service does not inherit your interactive shell setup.
Validate, load, and start it:
sudo systemd-analyze verify /etc/systemd/system/notes-app.service
sudo systemctl daemon-reload
sudo systemctl enable --now notes-app
sudo systemctl status notes-app --no-pager
sudo journalctl -u notes-app -n 50 --no-pager
curl --fail http://127.0.0.1:3000/health
The unit should be enabled and active. The local health request must succeed before Nginx is involved.
Now replace the static location / in the Nginx server block:
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
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;
}
Validate and reload:
sudo nginx -t
sudo systemctl reload nginx
curl -I https://notes.example.com
A 502 Bad Gateway means Nginx could not get a usable response from the upstream. Check systemctl status notes-app, the journal, ss -lntp, and the configured port. Do not open port 3000 in UFW as a workaround.
For a code rollback, point /srv/notes-app/current at the previous tested release and restart notes-app. For a unit or Nginx rollback, restore the last working file, validate it, then reload or restart.
Your action is to reboot the Droplet during a safe learning window. After reconnecting, verify the service is active and the public HTTPS health endpoint still works.
Lesson completed