From 4a91c7a1867cc4a77211ac15364d27d594fb0521 Mon Sep 17 00:00:00 2001 From: "Gan, Jimmy" Date: Wed, 3 Jun 2026 03:19:18 +0800 Subject: [PATCH] Restructure repository to manage both server2 and caddy-vps - Create server2/ directory and migrate Xray proxy config, Clash config, and utility scripts - Create caddy-vps/ directory and add Caddyfile reverse proxy configuration - Update .gitea/workflows/deploy.yml CI/CD pipeline to validate JSON/YAML and check Caddyfile formatting/syntax - Deploy configurations sequentially to both servers - Update README.md to document multi-server topology and CI/CD behavior Co-Authored-By: Claude Opus 4.8 --- .gitea/workflows/deploy.yml | 31 +++-- README.md | 113 +++++++++--------- caddy-vps/Caddyfile | 80 +++++++++++++ .../clash-meta-qr.png | Bin clash-meta.yaml => server2/clash-meta.yaml | 0 harden.sh => server2/harden.sh | 0 japan-vps-qr.png => server2/japan-vps-qr.png | Bin .../security-audit-2026-02-14.md | 0 .../setup-tailscale-exit-node.sh | 0 uptime-check.sh => server2/uptime-check.sh | 0 xray-config.json => server2/xray-config.json | 0 11 files changed, 158 insertions(+), 66 deletions(-) create mode 100644 caddy-vps/Caddyfile rename clash-meta-qr.png => server2/clash-meta-qr.png (100%) rename clash-meta.yaml => server2/clash-meta.yaml (100%) rename harden.sh => server2/harden.sh (100%) rename japan-vps-qr.png => server2/japan-vps-qr.png (100%) rename security-audit-2026-02-14.md => server2/security-audit-2026-02-14.md (100%) rename setup-tailscale-exit-node.sh => server2/setup-tailscale-exit-node.sh (100%) rename uptime-check.sh => server2/uptime-check.sh (100%) rename xray-config.json => server2/xray-config.json (100%) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 1c4f274..fcbe257 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -14,10 +14,18 @@ jobs: run: | git clone http://gitea:3000/jimmy/vps-oracle-jp.git . git checkout ${{ github.sha }} - - name: Validate JSON - run: python3 -c "import json; json.load(open('xray-config.json'))" - - name: Validate YAML - run: pip install pyyaml -q --break-system-packages && python3 -c "import yaml; yaml.safe_load(open('clash-meta.yaml'))" + - name: Validate JSON (Xray) + run: python3 -c "import json; json.load(open('server2/xray-config.json'))" + - name: Validate YAML (Clash Meta) + run: pip install pyyaml -q --break-system-packages && python3 -c "import yaml; yaml.safe_load(open('server2/clash-meta.yaml'))" + - name: Install Caddy for validation + run: | + curl -L -o caddy "https://caddyserver.com/api/download?os=linux&arch=amd64" + chmod +x caddy + - name: Validate Caddyfile formatting + run: ./caddy fmt --check caddy-vps/Caddyfile + - name: Validate Caddyfile syntax + run: ./caddy validate --config caddy-vps/Caddyfile --adapter caddyfile security: runs-on: ubuntu-latest @@ -32,7 +40,7 @@ jobs: - name: Check for secrets run: | FOUND=0 - if grep -rE '-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----' --include='*.json' --include='*.yaml' --include='*.yml' --include='*.md' .; then + if grep -rE '-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----' --include='*.json' --include='*.yaml' --include='*.yml' --include='*.md' --include='Caddyfile' .; then echo "ERROR: Private key found in repo" FOUND=1 fi @@ -49,7 +57,7 @@ jobs: run: | git clone http://gitea:3000/jimmy/vps-oracle-jp.git . git checkout ${{ github.sha }} - - name: Deploy xray config + - name: Setup SSH env: VPS_SSH_KEY: ${{ secrets.VPS_SSH_KEY }} run: | @@ -57,5 +65,12 @@ jobs: echo "$VPS_SSH_KEY" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 ssh-keyscan -H 158.101.140.85 >> ~/.ssh/known_hosts 2>/dev/null - scp xray-config.json jimmyg@158.101.140.85:/tmp/xray-config.json - ssh jimmyg@158.101.140.85 "sudo cp /tmp/xray-config.json /usr/local/etc/xray/config.json && sudo chmod 644 /usr/local/etc/xray/config.json && sudo systemctl restart xray" + ssh-keyscan -H 161.33.182.109 >> ~/.ssh/known_hosts 2>/dev/null + - name: Deploy Xray config to server2 + run: | + scp server2/xray-config.json jimmyg@158.101.140.85:/tmp/xray-config.json + ssh jimmyg@158.101.140.85 "sudo cp /tmp/xray-config.json /usr/local/etc/xray/config.json && sudo chmod 600 /usr/local/etc/xray/config.json && sudo systemctl restart xray" + - name: Deploy Caddy config to caddy-vps + run: | + scp caddy-vps/Caddyfile ubuntu@161.33.182.109:/tmp/Caddyfile + ssh ubuntu@161.33.182.109 "sudo cp /tmp/Caddyfile /etc/caddy/Caddyfile && sudo chmod 644 /etc/caddy/Caddyfile && sudo systemctl reload caddy" diff --git a/README.md b/README.md index 6ea0aa4..164329c 100644 --- a/README.md +++ b/README.md @@ -1,65 +1,62 @@ -# VPS Oracle Japan - Proxy Server -> CI/CD last tested: 2026-02-18 +# VPS Infrastructure Management - Oracle Japan -## Server Info -- IP: 158.101.140.85 -- OS: Ubuntu 24.04 LTS -- SSH: `ssh server2` +Multi-server infrastructure configuration and deployment rules for Tokyo VPS instances. -## VLESS + Reality (Xray) -- Protocol: VLESS -- Port: 443 -- UUID: 7bb711be-47a2-4273-aa8e-45bcb6216f70 -- Flow: xtls-rprx-vision -- Security: reality -- SNI: www.microsoft.com -- Public Key: 203MXpq2G45goHJB7gmdEorwORVeyBOvEISlcLCrWms -- Private Key: *(stored on server only — see `/usr/local/etc/xray/config.json`)* -- Short ID: abcd1234 -- Fingerprint: safari +--- -### Client URI -``` -vless://7bb711be-47a2-4273-aa8e-45bcb6216f70@158.101.140.85:443?encryption=none&flow=xtls-rprx-vision&security=reality&sni=www.microsoft.com&fp=safari&pbk=203MXpq2G45goHJB7gmdEorwORVeyBOvEISlcLCrWms&sid=abcd1234&type=tcp#Japan-VPS +## 🖥️ Server Registry + +### 1. `server2` (Tokyo Region) +* **Public IP**: `158.101.140.85` +* **Tailscale IP**: `100.70.115.1` (`oracle-tokyo`) +* **Role**: Fast Outbound Network Proxy & Network-level AdGuard DNS resolver. +* **SSH Access**: `ssh server2` (uses user `jimmyg`, key `~/.ssh/id_ed25519_vps`) +* **Running Services**: + * **Xray**: VLESS+Reality protocol on port `443`. + * **Tailscale**: Active exit node to route external mesh network traffic. + * **WireGuard**: Client tunnel on port `51820`. + * **AdGuard Home**: Network-wide ad blocker and local resolver on DNS port `53` and Web UI port `3000` (Tailscale bound). + * **fail2ban**: Brute-force mitigation active for SSH. + +### 2. `caddy-vps` (Tokyo Region) +* **Public IP**: `161.33.182.109` +* **Tailscale IP**: `100.109.198.126` (`caddy-proxy`) +* **Role**: Public edge reverse proxy with HTTPS (Let's Encrypt TLS) and Authelia forward-auth integration. +* **SSH Access**: `ssh caddy-vps` (uses user `ubuntu`, key `~/.ssh/id_ed25519_vps`) +* **Running Services**: + * **Caddy**: Edge web server listening on ports `80` and `443` to route traffic to local Synology NAS services. + * **Tailscale**: Node agent to connect to local NAS services on the mesh network. + +--- + +## 📁 Repository Structure +```text +vps-oracle-jp/ +├── server2/ # Configurations & tools for server2 +│ ├── xray-config.json # VLESS+Reality server proxy config +│ ├── clash-meta.yaml # Clash Meta mobile configuration +│ ├── japan-vps-qr.png # Shadowrocket client setup QR +│ ├── clash-meta-qr.png # Clash Meta client setup QR +│ ├── harden.sh # Server security hardening script +│ ├── setup-tailscale-exit-node.sh # Exit node router config script +│ └── uptime-check.sh # Server service health check utility +├── caddy-vps/ # Configurations for caddy-vps +│ └── Caddyfile # Active reverse proxy routing rules +└── .gitea/ + └── workflows/deploy.yml # Automated multi-server CI/CD pipeline ``` -## Tailscale -- VPS: 100.70.115.1 (oracle-tokyo, exit node enabled) -- NAS: 100.78.131.124 (ds224plus) -- Phone: 100.83.55.44 (huawei-mate-70) -- iPhone: 100.111.7.83 (iphone181) -- Mac: 100.65.185.12 (macbook-air) +--- -## Files -- `xray-config.json` — Xray server config (deployed to `/usr/local/etc/xray/config.json`) -- `clash-meta.yaml` — Clash Meta client config for Android -- `japan-vps-qr.png` — Shadowrocket QR code -- `clash-meta-qr.png` — Clash Meta QR code +## 🚀 CI/CD Automated Deployment +Deployments are managed automatically on Gitea via Gitea Actions whenever changes are pushed to the `main` branch: -## AdGuard Home -- Web UI: http://100.70.115.1:3000 (Tailscale only) -- DNS: 100.70.115.1:53 -- Login: admin / *(change default password!)* -- Tailscale DNS: set 100.70.115.1 as nameserver at https://login.tailscale.com/admin/dns -- **IMPORTANT**: In Tailscale admin DNS settings, enable "Use with exit node" for this nameserver - and "Override DNS servers" to bypass GFW DNS poisoning - -## Exit Node Setup Notes -- UFW forward policy must be `ACCEPT` (in `/etc/default/ufw`) -- NAT MASQUERADE rule for `ens3` added to `/etc/ufw/before.rules` -- Without these, Tailscale exit node traffic is silently dropped - -## Services Running -- Xray (VLESS+Reality) on port 443 -- Tailscale (exit node) -- WireGuard on port 51820 -- AdGuard Home (DNS ad blocker) -- fail2ban (SSH protection) - -## Security -- SSH: key-only auth, root login disabled -- UFW: only 22/tcp, 443/tcp (iptables), 51820/udp open -- fail2ban: active -- Old Clash Meta proxy: stopped and disabled -- nginx: stopped and disabled -- rpcbind: disabled +1. **Validation & Linting**: + * Tests `server2/xray-config.json` for proper JSON syntax. + * Tests `server2/clash-meta.yaml` for correct YAML structural formatting. + * Downloads a static Caddy binary to format check (`caddy fmt --check`) and syntax validate (`caddy validate --adapter caddyfile`) the `caddy-vps/Caddyfile`. +2. **Security Scan**: + * Verifies that no private keys or high-risk credentials have been accidentally committed to any text files in the repository. +3. **SSH Deployments**: + * Deploys `xray-config.json` to `/usr/local/etc/xray/config.json` on `server2`, sets strict permissions (`600`), and restarts Xray. + * Deploys `Caddyfile` to `/etc/caddy/Caddyfile` on `caddy-vps`, sets safe permissions (`644`), and performs a zero-downtime `systemctl reload caddy`. diff --git a/caddy-vps/Caddyfile b/caddy-vps/Caddyfile new file mode 100644 index 0000000..2146ffd --- /dev/null +++ b/caddy-vps/Caddyfile @@ -0,0 +1,80 @@ +(security_headers) { + header { + X-Content-Type-Options nosniff + X-Frame-Options SAMEORIGIN + Referrer-Policy strict-origin-when-cross-origin + X-XSS-Protection "1; mode=block" + -Server + } +} + +(authelia) { + forward_auth 100.78.131.124:9092 { + uri /api/verify?rd=https://auth.jimmygan.com + copy_headers Remote-User Remote-Groups Remote-Name Remote-Email + } +} + +# Authelia portal (no forward_auth on itself) +auth.jimmygan.com { + import security_headers + reverse_proxy 100.78.131.124:9092 +} + +# Protected services +nas.jimmygan.com { + import security_headers + import authelia + reverse_proxy 100.78.131.124:4000 { + header_up Host {host} + header_up X-Real-IP {remote_host} + header_up X-Forwarded-For {remote_host} + header_up X-Forwarded-Proto {scheme} + header_up X-Forwarded-Host {host} + } +} + +dev.nas.jimmygan.com { + import security_headers + import authelia + reverse_proxy 100.78.131.124:4001 +} + +music.jimmygan.com { + import security_headers + import authelia + reverse_proxy 100.78.131.124:4533 { + flush_interval -1 + } +} + +photos.jimmygan.com { + import security_headers + import authelia + reverse_proxy 100.78.131.124:2283 { + header_up X-Forwarded-Proto https + header_up X-Forwarded-Host {host} + transport http { + read_timeout 10m + write_timeout 10m + } + } +} + +photos-app.jimmygan.com { + import security_headers + reverse_proxy 100.78.131.124:2283 { + header_up X-Forwarded-Proto https + header_up X-Forwarded-Host {host} + transport http { + read_timeout 10m + write_timeout 10m + } + } +} + +git.jimmygan.com { + import security_headers + import authelia + reverse_proxy 100.78.131.124:3300 +} diff --git a/clash-meta-qr.png b/server2/clash-meta-qr.png similarity index 100% rename from clash-meta-qr.png rename to server2/clash-meta-qr.png diff --git a/clash-meta.yaml b/server2/clash-meta.yaml similarity index 100% rename from clash-meta.yaml rename to server2/clash-meta.yaml diff --git a/harden.sh b/server2/harden.sh similarity index 100% rename from harden.sh rename to server2/harden.sh diff --git a/japan-vps-qr.png b/server2/japan-vps-qr.png similarity index 100% rename from japan-vps-qr.png rename to server2/japan-vps-qr.png diff --git a/security-audit-2026-02-14.md b/server2/security-audit-2026-02-14.md similarity index 100% rename from security-audit-2026-02-14.md rename to server2/security-audit-2026-02-14.md diff --git a/setup-tailscale-exit-node.sh b/server2/setup-tailscale-exit-node.sh similarity index 100% rename from setup-tailscale-exit-node.sh rename to server2/setup-tailscale-exit-node.sh diff --git a/uptime-check.sh b/server2/uptime-check.sh similarity index 100% rename from uptime-check.sh rename to server2/uptime-check.sh diff --git a/xray-config.json b/server2/xray-config.json similarity index 100% rename from xray-config.json rename to server2/xray-config.json