120 lines
4.2 KiB
Python
120 lines
4.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Install the lightweight front door and switch only /code/ to the JD tunnel."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import datetime
|
|
import pathlib
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import urllib.error
|
|
import urllib.request
|
|
|
|
|
|
SITE_CONFIG = pathlib.Path("/etc/nginx/sites-enabled/guanghulab")
|
|
WEB_ROOT = pathlib.Path("/var/www/guanghulab-front-door")
|
|
SOURCE_FILES = ("index.html", "styles.css", "robots.txt", "llms.txt", "sitemap.xml")
|
|
|
|
OLD_CODE_BLOCK = re.compile(
|
|
r""" # Forgejo 代码仓库
|
|
location /code/ \{
|
|
auth_request /auth/verify-signature;
|
|
proxy_pass http://127\.0\.0\.1:3001/;
|
|
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;
|
|
client_max_body_size 100m;
|
|
\}
|
|
""",
|
|
)
|
|
|
|
NEW_CODE_BLOCK = """ # 光湖代码频道 · 广州备案前门 → 京东个人子频道
|
|
location /code/ {
|
|
proxy_pass http://127.0.0.1:18088/code/;
|
|
proxy_http_version 1.1;
|
|
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_connect_timeout 5s;
|
|
proxy_read_timeout 300s;
|
|
proxy_send_timeout 300s;
|
|
client_max_body_size 256m;
|
|
}
|
|
"""
|
|
|
|
|
|
def run(*args: str) -> None:
|
|
subprocess.run(args, check=True)
|
|
|
|
|
|
def get_status(url: str) -> int:
|
|
request = urllib.request.Request(url, method="GET")
|
|
try:
|
|
with urllib.request.urlopen(request, timeout=15) as response:
|
|
return response.status
|
|
except urllib.error.HTTPError as error:
|
|
return error.code
|
|
|
|
|
|
def main() -> None:
|
|
if len(sys.argv) != 2:
|
|
raise SystemExit("usage: install-lite-front-door.py SOURCE_DIRECTORY")
|
|
source = pathlib.Path(sys.argv[1]).resolve()
|
|
if not SITE_CONFIG.is_file():
|
|
raise RuntimeError("active guanghulab nginx config unavailable")
|
|
for name in SOURCE_FILES:
|
|
if not (source / name).is_file():
|
|
raise RuntimeError(f"front-door source missing: {name}")
|
|
|
|
current = SITE_CONFIG.read_text(encoding="utf-8")
|
|
updated, replacements = OLD_CODE_BLOCK.subn(NEW_CODE_BLOCK, current)
|
|
if replacements == 0 and NEW_CODE_BLOCK.strip() not in current:
|
|
raise RuntimeError("expected legacy /code/ block not found")
|
|
if replacements > 1:
|
|
raise RuntimeError("multiple legacy /code/ blocks found")
|
|
|
|
stamp = datetime.datetime.now(datetime.UTC).strftime("%Y%m%dT%H%M%SZ")
|
|
backup_root = pathlib.Path("/var/backups/guanghu/front-door") / stamp
|
|
backup_root.mkdir(parents=True, mode=0o700)
|
|
shutil.copy2(SITE_CONFIG, backup_root / "guanghulab.nginx")
|
|
if WEB_ROOT.exists():
|
|
shutil.copytree(WEB_ROOT, backup_root / "web-root")
|
|
|
|
temporary_config = SITE_CONFIG.with_name(f"guanghulab.{stamp}.new")
|
|
temporary_config.write_text(updated, encoding="utf-8")
|
|
temporary_config.chmod(0o644)
|
|
temporary_config.replace(SITE_CONFIG)
|
|
|
|
WEB_ROOT.mkdir(parents=True, exist_ok=True)
|
|
for name in SOURCE_FILES:
|
|
destination = WEB_ROOT / name
|
|
shutil.copy2(source / name, destination)
|
|
destination.chmod(0o644)
|
|
|
|
try:
|
|
run("/usr/sbin/nginx", "-t")
|
|
run("/usr/bin/systemctl", "reload", "nginx")
|
|
if get_status("https://guanghulab.com/") != 200:
|
|
raise RuntimeError("front-door homepage verification failed")
|
|
if get_status("https://guanghulab.com/code/") not in (200, 303):
|
|
raise RuntimeError("code-channel public route verification failed")
|
|
if get_status("https://guanghulab.com/fifth-domain/api/v1/version") != 200:
|
|
raise RuntimeError("legacy Fifth Domain verification failed")
|
|
except Exception:
|
|
shutil.copy2(backup_root / "guanghulab.nginx", SITE_CONFIG)
|
|
if (backup_root / "web-root").exists():
|
|
shutil.rmtree(WEB_ROOT)
|
|
shutil.copytree(backup_root / "web-root", WEB_ROOT)
|
|
run("/usr/sbin/nginx", "-t")
|
|
run("/usr/bin/systemctl", "reload", "nginx")
|
|
raise
|
|
|
|
print(f"LIGHT_FRONT_DOOR_DEPLOYED backup={backup_root}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|