Runtime
Node.js 24 LTS
Framework
Express 5
Database
MariaDB 11.4
Process
PM2 + systemd
Start Building (Quickstart)
- SSH:
ssh root@172.233.88.37 - Upload code via SFTP / FileZilla / Cyberduck: host=
172.233.88.37, user=root, target=/opt/myapp_express/ - Ownership:
chown -R appuser:appuser /opt/myapp_express - Install:
sudo -iu appuser→cd /opt/myapp_express→pnpm install --prod(npm or yarn work too) - Restart:
exit→sudo -u appuser pm2 reload myapp_express
Operate (root)
Service status
systemctl status pm2-appuserApp logs
sudo -u appuser pm2 logs myapp_expressReload app
sudo -u appuser pm2 reload myapp_expressDB env
sudo cat /etc/myapp_express/envReference (paths & configs)
Runtime
Node.js 24 LTS (Express 5 needs Node 18+).Build tool
pnpm install --prod by default. npm install --omit=dev or yarn install --production work too — no compile step.Entry point
/opt/myapp_express/index.js (plain JS, no build).PM2 config
/opt/myapp_express/ecosystem.config.js — cluster mode, name=myapp_express, script=index.js. Reads /etc/myapp_express/env at start.systemd unit
/etc/systemd/system/pm2-appuser.service — auto-generated by pm2 startup; runs as appuser. PM2 then resurrects ecosystem.config.js.DB env file
/etc/myapp_express/env (mode 0640, root:appuser) — loaded by ecosystem.config.js, exposed to Express via process.env.App port
3000 (Express listen port). Nginx reverse-proxies :80 / :443 → :3000.Logs
sudo -u appuser pm2 logs myapp_express (rotated under ~appuser/.pm2/logs/). systemd journal: journalctl -u pm2-appuser.Profile / NODE_ENVadd
NODE_ENV=production to /etc/myapp_express/env; ecosystem.config.js auto-loads it.Redeployupload new source →
chown -R appuser:appuser /opt/myapp_express → sudo -iu appuser → cd /opt/myapp_express → pnpm install --prod → pm2 reload myapp_express (zero-downtime in cluster mode).