This commit is contained in:
2026-09-28 23:15:47 +05:30
commit 605c6a2e58
41 changed files with 4299 additions and 0 deletions
+58
View File
@@ -0,0 +1,58 @@
# 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.
+7
View File
@@ -0,0 +1,7 @@
# Include this inside the existing Apache virtual host.
# Do not add a public Listen for Node. TLS stays on Apache.
# Requires: a2enmod proxy proxy_http
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
+19
View File
@@ -0,0 +1,19 @@
[Unit]
Description=100kmph front desk
After=network.target mariadb.service
[Service]
Type=simple
User=hundredkmph
Group=hundredkmph
WorkingDirectory=/opt/hundredkmph/web
Environment=NODE_ENV=production
Environment=HOSTNAME=127.0.0.1
Environment=PORT=3000
EnvironmentFile=/etc/hundredkmph/web.env
ExecStart=/usr/bin/node /opt/hundredkmph/web/server.js
Restart=on-failure
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target
+16
View File
@@ -0,0 +1,16 @@
-- Run as an admin, before the app starts.
-- Do not create a remote root, and do not grant this user '@'%'.
-- The app user cannot DELETE and cannot apply DDL.
-- Soft-delete is an UPDATE of deleted_at.
-- Replace the password, then: chmod 600 this file if you fill in a real password.
CREATE DATABASE IF NOT EXISTS hundredkmph CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS 'hundredkmph'@'localhost' IDENTIFIED BY 'replace-with-a-long-random-password';
GRANT SELECT, INSERT, UPDATE ON hundredkmph.* TO 'hundredkmph'@'localhost';
FLUSH PRIVILEGES;
-- Then apply the migration as an admin (the app user cannot):
-- mariadb hundredkmph < /opt/hundredkmph/src/web/db/001_init.sql