# Deploy 100kmph web on Debian 12 Apache and MariaDB are already on the box. Add Node.js 20 LTS. The Next process listens on `127.0.0.1:3000` only. Apache is the public front. Do not open port 3000. ## MariaDB 1. Edit the password in [mariadb-grants.sql](mariadb-grants.sql). 2. Apply it as an admin: `mariadb < mariadb-grants.sql` 3. Apply [../db/001_init.sql](../db/001_init.sql) as an admin, not as `hundredkmph`. 4. Do not enable remote root. The app user gets `SELECT`, `INSERT`, and `UPDATE` on `hundredkmph` from `localhost` only. ## App process Build on the server (or copy a build from a machine with the same Node major version): ```sh cd /opt/hundredkmph/src/web npm ci npm run build mkdir -p /opt/hundredkmph/web rm -rf /opt/hundredkmph/web/* cp -a .next/standalone/. /opt/hundredkmph/web/ mkdir -p /opt/hundredkmph/web/.next cp -a .next/static /opt/hundredkmph/web/.next/static ``` Create a system user and a root-only env file: ```sh useradd --system --home /opt/hundredkmph/web --shell /usr/sbin/nologin hundredkmph install -d -m 0750 -o root -g root /etc/hundredkmph install -m 0600 -o root -g root /dev/null /etc/hundredkmph/web.env ``` `/etc/hundredkmph/web.env` contains only: ``` DATABASE_URL=mysql://hundredkmph:THE_PASSWORD@127.0.0.1:3306/hundredkmph SYNC_TOKEN=a-long-random-secret ``` systemd reads that file as root before dropping to `hundredkmph`. `HOSTNAME=127.0.0.1` and `PORT=3000` are set in [hundredkmph-web.service](hundredkmph-web.service), so the process does not listen on a public interface. ```sh cp hundredkmph-web.service /etc/systemd/system/hundredkmph-web.service systemctl daemon-reload systemctl enable --now hundredkmph-web ``` `npm start` is the non-standalone equivalent: `next start -H 127.0.0.1 -p 3000`. ## Apache Leave the existing TLS virtual host in place. Enable `proxy` and `proxy_http`, then include [apache-hundredkmph.conf](apache-hundredkmph.conf) inside that virtual host. WebSocket upgrade is not required. `mod_proxy` appends the client address to `X-Forwarded-For`. The status lookup uses the last address in that header.