Systems & security
Linux in Production
How I deploy, supervise and diagnose MartialXPro on its Ubuntu host using Nginx, PM2, system services, permissions and logs.

Why this is its own project
An API can work locally and still fail on its host because of process state, permissions, proxy routing or service startup. This case study isolates that operational layer from the application itself.
The examples come from the Ubuntu host serving MartialXPro.
The host
- Web layer
- Nginx: reverse proxy, TLS termination, static content
- Process layer
- PM2: supervision, restart on failure and on boot
- Runtime
- Node.js, configured entirely through environment variables
- Access
- SSH with key-based authentication
- Diagnostics
- PM2 process logs and Nginx access/error logs
Nginx as the front door
Nginx sits in front of the Node process rather than exposing the application port directly. That gives one place to terminate TLS, one place to decide what is proxied and what is served as a static file, and one place to control the headers the application sees.
Most of the configuration work was in the details: correct proxy_pass upstreams, forwarding the headers the application depends on, and keeping the split between API traffic and static content unambiguous. A reverse proxy that quietly rewrites part of a request produces bugs that look like application bugs.
Keeping the process alive
PM2 supervises the Node.js application. It restarts the process if it exits, brings it back after a reboot and gives a consistent place to read runtime logs from. Combined with environment-variable configuration, that means a server restart requires no manual steps to get back to a serving state.
Hardening the box
The security work is not a separate phase bolted on at the end. It is part of the host's default configuration. Coming from CEHP and WAPT coursework, the baseline I apply is the one I would otherwise be probing for gaps in:
- Key-based SSH onlyAdministrative SSH access uses key-based authentication; password authentication is disabled.
- Least-privilege file permissionsApplication files, log directories and environment files are owned and readable only by the accounts that genuinely need them, rather than using blanket 777 permissions to make an error go away.
- Minimal exposed surfaceOnly the ports that need to be reachable are reachable. Everything else stays closed at the firewall and security-group level.
- No secrets in the repositoryCredentials and environment-specific configuration live in environment variables on the host, never in version control.
- Separation of deploy and runtime accountsThe account that ships code and the account that runs it are distinct, so a compromise of one is not automatically a compromise of the other.
Operating it
Operational diagnosis starts with PM2 process state and application logs, then Nginx access and error logs, service status, file ownership and environment configuration. Recurring issues have included deploy and runtime ownership mismatches, proxy assumptions and startup ordering after reboots.
Current learning priorities are Docker for repeatable runtime packaging and Terraform for describing infrastructure. Orchestration is a later decision, contingent on the platform needing multiple services or hosts.