From 1106c03feb9bc4e3d3bd180ecb48ede02e6dab6e Mon Sep 17 00:00:00 2001 From: "soroush.asadi" Date: Mon, 15 Jun 2026 10:46:32 +0330 Subject: [PATCH] docs(deploy): sync nginx/cert/DNS docs with the real working setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reflect what the live deploy actually required: - cert must be NESTED under an already-mounted dir (/etc/ssl/soroushasadi/flatrender/) — mirror-nginx mounts cert dirs individually, so a fresh /etc/ssl/flatrender is invisible in the container. - after a sed -i edit of the bind-mounted nginx.conf, restart (not reload) — inode swap. - DNS: box is behind NAT (171.22.25.73 private; public via edge/CDN 185.239.1.100 or direct 31.171.101.x) — register the domain the same way the other sites enter. - local SNI test command to verify routing bypassing DNS. Co-Authored-By: Claude Opus 4.8 --- deploy/README.md | 31 +++++++++++++++++++------ deploy/mirror-nginx-flatrender.conf | 36 +++++++++++++++++++++-------- 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index cd0a03b..9909718 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -19,15 +19,32 @@ Stack: gateway · identity · content · studio (.NET/Go) · file · render · n ## One-time setup (do these BEFORE the first `git push gitea master`) -1. **DNS** — three A-records → server IP: `flatrender.ir`, `api.flatrender.ir`, - `storage.flatrender.ir` (+ optional `www`). -2. **TLS cert** — place a cert covering all three names at - `/etc/ssl/flatrender/fullchain.pem` + `/etc/ssl/flatrender/privateKey.pem` - (wildcard `*.flatrender.ir` + apex, or a SAN cert — your usual issuance process). +1. **DNS** — this box sits BEHIND NAT: its interface IP is `171.22.25.73` (private), + public NAT IPs are `31.171.101.127/.211`, and inbound 443 normally arrives via the + edge/CDN `185.239.1.100` (same entry your other sites use, e.g. `meezi.ir`). So a new + domain must enter the SAME way the others do — either: + - register `flatrender.ir` + `api` + `storage` + `www` in that edge/CDN (origin = this + server) and point DNS there, **or** + - bypass the CDN and point DNS straight at the server's public IP (like the hokm `api` + subdomain does — "must bypass"). + Pointing DNS at a random/registrar IP shows that host's default page (e.g. a "not + licensed" page), NOT FlatRender. +2. **TLS cert** — ⚠️ mirror-nginx mounts cert dirs INDIVIDUALLY, so a fresh + `/etc/ssl/flatrender/` on the host is invisible inside the container. **Nest the cert + under an already-mounted dir** (the conf references this path): + ```bash + mkdir -p /etc/ssl/soroushasadi/flatrender + cp /fullchain.pem /etc/ssl/soroushasadi/flatrender/ + cp /privateKey.pem /etc/ssl/soroushasadi/flatrender/ + ``` + Cert must cover `flatrender.ir` + `api.` + `storage.` (wildcard `*.flatrender.ir` + apex, or SAN). 3. **mirror-nginx** — add the server blocks from [`mirror-nginx-flatrender.conf`](./mirror-nginx-flatrender.conf) - to the proxy's `http{}` block, then: + to the proxy's `http{}` (the host file is `/root/mirror-server/nginx/nginx.conf`), then: `docker exec mirror-nginx nginx -t && docker exec mirror-nginx nginx -s reload`. - (Do this after the first deploy is up, or it'll 502 until the ports are live.) + ⚠️ If you edited the conf with `sed -i` (which swaps the file inode), the running + container keeps the old inode → `docker restart mirror-nginx` instead (~3s blip). + Verify locally (bypasses DNS): `curl -sk --resolve flatrender.ir:443:127.0.0.1 https://flatrender.ir/ | head -c 60` + must show ``. (Do this after the first deploy is up, or it 502s.) 4. **ENV_FILE secret** — at `…/soroushdes/flatrender/settings/secrets`, create `ENV_FILE` from [`ENV_FILE.production.example`](./ENV_FILE.production.example) (already filled for flatrender.ir; generate each secret with `openssl rand -hex 32`). diff --git a/deploy/mirror-nginx-flatrender.conf b/deploy/mirror-nginx-flatrender.conf index 7d4d441..0b2208c 100644 --- a/deploy/mirror-nginx-flatrender.conf +++ b/deploy/mirror-nginx-flatrender.conf @@ -4,11 +4,27 @@ # Routes the three public domains to the FlatRender host ports on 171.22.25.73 # (FRONTEND_PORT / GATEWAY_PORT / MINIO_PORT from the deploy ENV_FILE). # -# TLS cert must exist first: /etc/ssl/flatrender/{fullchain.pem,privateKey.pem} -# covering flatrender.ir + api.flatrender.ir + storage.flatrender.ir -# (wildcard *.flatrender.ir + apex, or a SAN cert). +# The mirror-nginx config file lives on the HOST at /root/mirror-server/nginx/nginx.conf +# (bind-mounted read-only into the container). Add these blocks there. # -# Apply: docker exec mirror-nginx nginx -t && docker exec mirror-nginx nginx -s reload +# ⚠️ CERT-MOUNT TRAP: mirror-nginx mounts cert dirs INDIVIDUALLY +# (/etc/ssl/{soroushasadi,meezi,...}). A new /etc/ssl/soroushasadi/flatrender/ on the host is +# INVISIBLE inside the container → nginx -t "cannot load certificate". So NEST the +# flatrender cert under an already-mounted dir: +# mkdir -p /etc/ssl/soroushasadi/flatrender +# cp /fullchain.pem /privateKey.pem /etc/ssl/soroushasadi/flatrender/ +# The cert must cover flatrender.ir + api. + storage. (wildcard *.flatrender.ir + apex, +# or a SAN cert). +# +# ⚠️ After editing nginx.conf with `sed -i` (which replaces the file inode), the +# running container keeps the OLD inode → you must RESTART, not just reload: +# docker restart mirror-nginx # ~3s blip for all sites +# A plain edit that keeps the inode + reload is fine: +# docker exec mirror-nginx nginx -t && docker exec mirror-nginx nginx -s reload +# +# Test routing locally (bypasses DNS): +# curl -sk --resolve flatrender.ir:443:127.0.0.1 https://flatrender.ir/ | head -c 60 +# # must show: # ========================================================================== server { @@ -22,8 +38,8 @@ server { listen 443 ssl; http2 on; server_name flatrender.ir www.flatrender.ir; client_max_body_size 25m; - ssl_certificate /etc/ssl/flatrender/fullchain.pem; - ssl_certificate_key /etc/ssl/flatrender/privateKey.pem; + ssl_certificate /etc/ssl/soroushasadi/flatrender/fullchain.pem; + ssl_certificate_key /etc/ssl/soroushasadi/flatrender/privateKey.pem; location / { proxy_pass http://171.22.25.73:1600; proxy_http_version 1.1; @@ -41,8 +57,8 @@ server { listen 443 ssl; http2 on; server_name api.flatrender.ir; client_max_body_size 512m; # large uploads routed through the gateway - ssl_certificate /etc/ssl/flatrender/fullchain.pem; - ssl_certificate_key /etc/ssl/flatrender/privateKey.pem; + ssl_certificate /etc/ssl/soroushasadi/flatrender/fullchain.pem; + ssl_certificate_key /etc/ssl/soroushasadi/flatrender/privateKey.pem; location / { proxy_pass http://171.22.25.73:1605; proxy_http_version 1.1; @@ -61,8 +77,8 @@ server { listen 443 ssl; http2 on; server_name storage.flatrender.ir; client_max_body_size 512m; - ssl_certificate /etc/ssl/flatrender/fullchain.pem; - ssl_certificate_key /etc/ssl/flatrender/privateKey.pem; + ssl_certificate /etc/ssl/soroushasadi/flatrender/fullchain.pem; + ssl_certificate_key /etc/ssl/soroushasadi/flatrender/privateKey.pem; location / { proxy_pass http://171.22.25.73:1610; proxy_set_header Host $host;