feature/ci-cd #70
@@ -4,7 +4,8 @@ Automatic staging on a **self-hosted Gitea** machine: merge (or push) to **`mast
|
||||
|
||||
| Public URL | What |
|
||||
|------------|------|
|
||||
| `http://wixur.ir` | Staging app (port **80** → Docker nginx) |
|
||||
| `https://wixur.ir` | Staging app (port **443** → Windows nginx → Docker). Mobinnet: public **80** is the modem. |
|
||||
| `http://wixur.ir:8088` | HTTP fallback |
|
||||
| `http://wixur.ir:3000` | Gitea + container registry |
|
||||
|
||||
DNS `wixur.ir` must point at the **Windows** host. Production (`https://nudentic.ir` on Linux) is separate — see [`DEPLOY.md`](DEPLOY.md). Do **not** point `wixur.ir` at the Linux VPS.
|
||||
@@ -22,8 +23,9 @@ Build backend + frontend → push to Gitea registry
|
||||
↓
|
||||
docker compose pull + up -d (docker-compose.registry.yml)
|
||||
↓
|
||||
http://wixur.ir → portproxy :80 → nginx :18088 → frontend / backend → postgres
|
||||
http://wixur.ir:3000 → Gitea (native, no Docker)
|
||||
https://wixur.ir → Windows nginx :443 → 127.0.0.1:18088 → Docker nginx → app
|
||||
http://wixur.ir:8088 → portproxy :8088 → 127.0.0.1:18088 (fallback)
|
||||
http://wixur.ir:3000 → Gitea (native, no Docker)
|
||||
```
|
||||
|
||||
| Service | Image source |
|
||||
@@ -41,14 +43,14 @@ Frontend public URLs are **baked in at build time** via `PUBLIC_BASE_URL`. After
|
||||
|
||||
DNS A record for `wixur.ir` → Windows IP (already done if `http://wixur.ir:3000` and `:8088` work).
|
||||
|
||||
On Windows (Admin PowerShell): portproxy **80 → 18088**, firewall + router **port 80** — see §6–7.
|
||||
On Windows: host nginx on **80** proxies to Docker **18088** ([`nginx/windows-edge-http.conf`](nginx/windows-edge-http.conf)). Remove portproxy on **80** (keep **8088** as fallback). Router must forward **80**. See §7.
|
||||
|
||||
In Gitea → repo → **Settings → Actions → Variables**:
|
||||
|
||||
- `PUBLIC_BASE_URL` = `http://wixur.ir`
|
||||
- `PUBLIC_BASE_URL` = `https://wixur.ir`
|
||||
- `STAGING_HTTP_PORT` = `80` (optional; workflow default is 80)
|
||||
|
||||
On disk: `FRONTEND_URL=http://wixur.ir` in `C:\dyolink\secrets\backend.staging.env`.
|
||||
On disk: `FRONTEND_URL=https://wixur.ir` and `COOKIE_SECURE=true` in `C:\dyolink\secrets\backend.staging.env`.
|
||||
|
||||
Then run the **Registry — build, push, deploy** workflow so the frontend image is rebuilt without `:8088`.
|
||||
|
||||
@@ -163,7 +165,7 @@ Rules:
|
||||
|------|---------|--------|
|
||||
| `REGISTRY_HOST` | `host.docker.internal:3000` | **Windows + Docker Desktop:** Docker runs in a Linux VM — `127.0.0.1` is the VM, not Gitea. Use `host.docker.internal:3000`. Gitea `ROOT_URL` should match this so registry login from CI works. Browsers and the Linux VPS use `http://wixur.ir:3000`. |
|
||||
| `REGISTRY_OWNER` | `admin` | Gitea user/org owning packages |
|
||||
| `PUBLIC_BASE_URL` | `http://wixur.ir` | How **users** open staging (no `:8088`, no trailing slash). Requires portproxy **80 → 18088** + router forward 80. |
|
||||
| `PUBLIC_BASE_URL` | `https://wixur.ir` | How **users** open staging (HTTPS on 443). No trailing slash. |
|
||||
| `DEPLOY_SECRETS_DIR` | `C:/dyolink/secrets` | Forward slashes OK on Windows |
|
||||
| `CLONE_HOST` | `127.0.0.1:3000` | Git clone (runs on Windows host, not inside Docker VM) |
|
||||
| `STAGING_HTTP_PORT` | `80` | Public HTTP port (portproxy). Optional; workflow default is 80. |
|
||||
@@ -190,44 +192,37 @@ New-NetFirewallRule -DisplayName "Dyolink Staging HTTP 80" -Direction Inbound -P
|
||||
New-NetFirewallRule -DisplayName "Dyolink Staging 8088" -Direction Inbound -Protocol TCP -LocalPort 8088 -Action Allow
|
||||
```
|
||||
|
||||
### 7. External access on Windows + Docker Desktop (portproxy)
|
||||
### 7. Port 80 = host nginx (not portproxy)
|
||||
|
||||
Gitea on **:3000** runs natively on Windows (`http://wixur.ir:3000`). Staging nginx binds **127.0.0.1:18088** (not 80). Windows **portproxy** maps public **80 → 18088** so users open **`http://wixur.ir`**. Do **not** bind Docker on 80 — portproxy already owns that port (`bind: access permissions` if you try).
|
||||
Gitea stays on **:3000**. Docker staging nginx binds **127.0.0.1:18088**. A **Windows nginx** (the 1.29.x you already have) listens on **80** and proxies to 18088. Config: [`nginx/windows-edge-http.conf`](nginx/windows-edge-http.conf).
|
||||
|
||||
If IIS or another service already listens on 80, stop it first or portproxy will fail.
|
||||
|
||||
Run **once** in **PowerShell as Administrator**:
|
||||
**Do not** run portproxy on port 80 at the same time — it will lose to nginx (404 / hang). Keep portproxy **8088 → 18088** as fallback.
|
||||
|
||||
```powershell
|
||||
# 1) Free port 80 from portproxy (nginx will bind 80)
|
||||
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=80
|
||||
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=80 connectaddress=127.0.0.1 connectport=18088
|
||||
# Keep :8088 as a fallback until http://wixur.ir works, then you can delete it:
|
||||
# netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=8088 connectaddress=127.0.0.1 connectport=18088
|
||||
netsh interface portproxy show all
|
||||
Start-Service iphlpsvc
|
||||
Set-Service iphlpsvc -StartupType Automatic
|
||||
|
||||
# 2) Confirm Docker staging is up
|
||||
curl.exe http://127.0.0.1:18088/health
|
||||
|
||||
# 3) Install windows-edge-http.conf into host nginx, then:
|
||||
# nginx -t
|
||||
# nginx -s reload
|
||||
# (paths depend on where nginx is installed)
|
||||
|
||||
# 4) Must print "healthy" (not 404)
|
||||
curl.exe http://127.0.0.1/health
|
||||
```
|
||||
|
||||
Verify on the Windows PC:
|
||||
Replace any **default_server** / leftover `server { listen 80; }` in the host nginx that returns 404, or this file will never win.
|
||||
|
||||
```powershell
|
||||
curl http://127.0.0.1:18088/health
|
||||
curl http://127.0.0.1/health
|
||||
```
|
||||
|
||||
From another machine (DNS `wixur.ir` → this PC):
|
||||
From another machine (after **router forward TCP 80** → this PC):
|
||||
|
||||
```bash
|
||||
curl http://wixur.ir/health
|
||||
```
|
||||
|
||||
If LAN works but the public hostname fails, add **router port forward 80** → Windows PC (same as Gitea **3000**).
|
||||
|
||||
To remove the HTTP proxy later:
|
||||
|
||||
```powershell
|
||||
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=80
|
||||
```
|
||||
**Mobinnet:** public **80** is the modem. Use **443** instead: router forward **TCP 443 → 192.168.1.100**, then `https://wixur.ir`. Let's Encrypt after mobile-data `/health` works (self-signed is enough for that test).
|
||||
|
||||
---
|
||||
|
||||
@@ -338,7 +333,8 @@ docker logs dyolink_frontend_staging --tail 50
|
||||
| `infrastructure/deploy.registry.env.example` | Manual deploy env template |
|
||||
| `infrastructure/database.staging.env.example` | Postgres secrets template |
|
||||
| `infrastructure/backend.staging.env.example` | API secrets template |
|
||||
| `infrastructure/nginx/http-only.conf` | HTTP reverse proxy for staging |
|
||||
| `infrastructure/nginx/http-only.conf` | HTTP reverse proxy **inside Docker** staging |
|
||||
| `infrastructure/nginx/windows-edge-http.conf` | Windows **host** nginx on port 80 → 18088 |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@ JWT_EXPIRES_IN=15m
|
||||
JWT_REFRESH_SECRET=another_long_random_secret_different_from_JWT_SECRET
|
||||
JWT_REFRESH_EXPIRES_IN=30d
|
||||
|
||||
# CORS, cookies, and invite links — must match how users open the app (nginx host port)
|
||||
FRONTEND_URL=http://wixur.ir
|
||||
# CORS, cookies, and invite links — must match how users open the app
|
||||
FRONTEND_URL=https://wixur.ir
|
||||
|
||||
# HTTP staging — keep false unless you terminate TLS in front of the app
|
||||
COOKIE_SECURE=false
|
||||
# TLS is terminated on Windows nginx :443 — cookies must be Secure
|
||||
COOKIE_SECURE=true
|
||||
|
||||
# SMS (sms.ir)
|
||||
SMS_IR_API_KEY=CHANGE_ME_SMS_IR_API_KEY
|
||||
|
||||
78
infrastructure/nginx/windows-edge-http.conf
Normal file
78
infrastructure/nginx/windows-edge-http.conf
Normal file
@@ -0,0 +1,78 @@
|
||||
# Windows host nginx.conf — paste over
|
||||
# C:\tools\nginx-1.29.5\conf\nginx.conf
|
||||
#
|
||||
# :80 — LAN / 127.0.0.1 only (Mobinnet keeps public :80 for the modem)
|
||||
# :443 — public https://wixur.ir (router must forward 443 → this PC)
|
||||
#
|
||||
# Put Let's Encrypt PEMs in conf\ssl\ (win-acme --pemfilesname wixur):
|
||||
# ssl\wixur-chain.pem
|
||||
# ssl\wixur-key.pem
|
||||
#
|
||||
# After save: nginx -t then restart nginx
|
||||
# curl.exe https://wixur.ir/health → healthy
|
||||
# (curl to 127.0.0.1:443 fails name-check; cert is for wixur.ir)
|
||||
|
||||
#user nobody;
|
||||
worker_processes 1;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
client_max_body_size 50M;
|
||||
|
||||
# Shared proxy to Docker staging
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
server_name wixur.ir www.wixur.ir localhost 127.0.0.1;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:18088;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
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_read_timeout 300;
|
||||
proxy_connect_timeout 300;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
server_name wixur.ir www.wixur.ir localhost 127.0.0.1;
|
||||
|
||||
ssl_certificate ssl/wixur-chain.pem;
|
||||
ssl_certificate_key ssl/wixur-key.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:18088;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
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_read_timeout 300;
|
||||
proxy_connect_timeout 300;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
infrastructure/scripts/windows-renew-wixur-cert.cmd
Normal file
11
infrastructure/scripts/windows-renew-wixur-cert.cmd
Normal file
@@ -0,0 +1,11 @@
|
||||
@echo off
|
||||
REM Run as Administrator. Stops nginx so win-acme can bind 443 (TLS-ALPN),
|
||||
REM renews, then starts nginx again. Point the win-acme scheduled task here
|
||||
REM instead of calling wacs.exe directly.
|
||||
cd /d C:\tools\nginx-1.29.5
|
||||
taskkill /F /IM nginx.exe >nul 2>&1
|
||||
timeout /t 2 /nobreak >nul
|
||||
cd /d C:\tools\win-acme
|
||||
wacs.exe --renew --closeonfinish
|
||||
cd /d C:\tools\nginx-1.29.5
|
||||
start "" nginx.exe
|
||||
Reference in New Issue
Block a user