diff --git a/source/server/routes/auth.ts b/source/server/routes/auth.ts index 5663621..d427d6c 100644 --- a/source/server/routes/auth.ts +++ b/source/server/routes/auth.ts @@ -9,7 +9,7 @@ import { isSuperAdmin } from '../roles'; const router = Router(); -const ACCESS_TOKEN_TTL = '1h'; +const ACCESS_TOKEN_TTL = '10s'; const COOKIE_DOMAIN = process.env.COOKIE_DOMAIN ?? '.rokojori.com'; const RESET_BASE_URL = process.env.RESET_BASE_URL ?? 'https://account.rokojori.com'; const ACCOUNT_BASE_URL = process.env.RESET_BASE_URL ?? 'https://account.rokojori.com'; diff --git a/workspace/add-subdomain.html b/workspace/add-subdomain.html new file mode 100644 index 0000000..2c25033 --- /dev/null +++ b/workspace/add-subdomain.html @@ -0,0 +1,440 @@ + + +
+ + +Guide
+
+ Step-by-step checklist for deploying a new Node.js service as a
+ subdomain.rokojori.com on Server A.
+ Fill in the variables below — all commands update automatically.
+
Fill these in once and every command in the guide updates.
+
+ If any other rokojori site loads resources from this service (fonts, CSS, JSON,
+ images) via a browser request — @import, fetch,
+ <img src> etc. — the browser enforces the
+ same-origin policy and blocks the
+ response unless the server sends an Access-Control-Allow-Origin
+ header. Services that only serve their own pages and API calls to their own
+ frontend do not need CORS.
+
*
+ Access-Control-Allow-Origin: * allows any website on the internet
+ to load your resources. For public CDN assets that is acceptable, but for
+ rokojori services restrict it to known origins.
+
+ Because the header cannot carry a wildcard pattern like
+ *.rokojori.com, the server must check the incoming
+ Origin header against an allowlist and echo back the matched
+ origin. Unrecognised origins receive no header and the browser blocks them.
+
Add this to source/server/index.ts before the routes that need it:
const CORS_ALLOWED: Array<string | RegExp> = [
+ /^https?:\/\/([\w-]+\.)?rokojori\.com$/, // all *.rokojori.com subdomains
+ // 'https://someother.site', // add extra origins here
+];
+
+function allowCors(
+ req: express.Request,
+ res: express.Response,
+ next: express.NextFunction
+): void
+{
+ const origin = req.headers.origin;
+ if ( origin && CORS_ALLOWED.some( rule =>
+ typeof rule === 'string' ? rule === origin : rule.test( origin )
+ ) )
+ {
+ res.set( 'Access-Control-Allow-Origin', origin );
+ }
+ next();
+}
+
+// Apply before the routes that serve cross-origin resources:
+app.use( '/your-public-route', allowCors );
+
+ /^https?:\/\/([\w-]+\.)?rokojori\.com$/ accepts:
+ https://rokojori.com,
+ https://roject.rokojori.com,
+ https://styles.rokojori.com, and so on.
+ HTTP is included so local dev with a mapped host still works.
+ Extend CORS_ALLOWED with additional strings or regexes for
+ any external sites that need access.
+
+ Log in to community.rokojori.com,
+ click New Repository, name it (e.g. subdomain),
+ set it to private, and copy the clone URL.
+ Do not initialise with a README — the local project is already set up.
+
Create this at the project root before the first commit:
+node_modules/
+dist/
+build/
+.env
+storage/
+ git init
+git add .
+git commit -m "init"
+git remote add origin https://community.rokojori.com/Rokojori/subdomain.git
+git push -u origin main
+ + Log in to IONOS → Domains & SSL → rokojori.com + → DNS. Add a new record: +
+Type: A
+Name: subdomain
+Value: <Server A IP>
+TTL: 300
+
+ Wait a few minutes for propagation before running certbot.
+ Verify with ping subdomain.rokojori.com from any machine.
+
ssh root@<Server A IP>
+
+cd /opt
+git clone https://community.rokojori.com/Rokojori/subdomain.git subdomain
+cd subdomain
+ npm install
+ node scripts/copy-pages.js
+
+ Copy the contents from your local .env and paste them on the server.
+ Update any values that differ in production (port, secrets, URLs).
+
nano .env
+ # example for styles.rokojori.com
+mkdir -p storage/fonts
+
+ Run the server once manually to confirm it starts. Kill it with
+ Ctrl+C before moving to the systemd step — leave it
+ running and the port will conflict.
+
npm run dev
+# → service running on http://localhost:PORT
+# Ctrl+C to stop
+ nano /etc/nginx/sites-available/subdomain.rokojori.com
+ server {
+ listen 80;
+ server_name subdomain.rokojori.com;
+
+ location / {
+ proxy_pass http://localhost:PORT;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection 'upgrade';
+ 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;
+ proxy_cache_bypass $http_upgrade;
+ }
+}
+ ln -s /etc/nginx/sites-available/subdomain.rokojori.com \
+ /etc/nginx/sites-enabled/subdomain.rokojori.com
+
+nginx -t
+systemctl reload nginx
+
+ The --nginx plugin handles the ACME HTTP-01 challenge
+ through nginx directly — the app does not need to be running.
+ When prompted whether to redirect HTTP to HTTPS, choose
+ Redirect (option 2).
+
certbot --nginx -d subdomain.rokojori.com
+ + Certbot modifies the nginx config in-place, adding TLS directives and + an HTTP→HTTPS redirect block. It also installs a systemd timer for + automatic renewal — no extra setup needed. +
++ Certbot updates the config automatically, but always verify before reloading: +
+nginx -t
+systemctl reload nginx
+ curl -I https://subdomain.rokojori.com
+
+ Expect HTTP/2 200 (or 502 if the app is not yet running — that is fine at this stage).
+
nano /etc/systemd/system/service-name.service
+ [Unit]
+Description=service-name
+After=network.target
+
+[Service]
+Type=simple
+WorkingDirectory=/opt/subdomain
+ExecStart=/usr/bin/npx ts-node --project tsconfig.ts-node.json source/server/index.ts
+Restart=on-failure
+RestartSec=5
+StandardOutput=journal
+StandardError=journal
+
+[Install]
+WantedBy=multi-user.target
+
+ The .env file is loaded by import 'dotenv/config'
+ inside the app, so no EnvironmentFile= is needed.
+
systemctl daemon-reload
+systemctl enable service-name
+systemctl start service-name
+systemctl status service-name
+ journalctl -u service-name -f
+ cd /opt/subdomain
+git pull
+npm install
+node scripts/copy-pages.js # if applicable
+systemctl restart service-name
+ systemctl restart service-name # restart app
+systemctl status service-name # current state
+journalctl -u service-name -n 100 # last 100 log lines
+nginx -t # validate nginx config
+systemctl reload nginx # apply nginx changes
+
+ Certbot installs a systemd timer (certbot.timer) that
+ renews certificates automatically before expiry. Check its status with:
+
systemctl status certbot.timer
+