Update Dockerfile
Browse files- Dockerfile +87 -62
Dockerfile
CHANGED
|
@@ -1,5 +1,4 @@
|
|
| 1 |
FROM node:20-slim AS builder
|
| 2 |
-
|
| 3 |
WORKDIR /app
|
| 4 |
RUN apt-get update && apt-get install -y git python3 make g++ && rm -rf /var/lib/apt/lists/*
|
| 5 |
RUN git clone --depth=1 https://github.com/decolua/9router.git .
|
|
@@ -7,26 +6,21 @@ RUN sed -i 's/sameSite: "lax"/sameSite: "none"/' src/app/api/auth/login/route.js
|
|
| 7 |
RUN cat > next.config.mjs << 'NEXTEOF'
|
| 8 |
const nextConfig = {
|
| 9 |
output: "standalone",
|
| 10 |
-
serverExternalPackages: ["better-sqlite3",
|
| 11 |
-
images:
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
config.watchOptions = { ...config.watchOptions, ignored: /[\/](logs|\.next)[\/]/ };
|
| 16 |
return config;
|
| 17 |
},
|
| 18 |
-
async headers()
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
{ source: "/v1/:path*", destination: "/api/v1/:path*" },
|
| 27 |
-
{ source: "/v1", destination: "/api/v1" }
|
| 28 |
-
];
|
| 29 |
-
}
|
| 30 |
};
|
| 31 |
export default nextConfig;
|
| 32 |
NEXTEOF
|
|
@@ -34,7 +28,8 @@ RUN npm install && npm run build
|
|
| 34 |
|
| 35 |
# ---- Runtime ----
|
| 36 |
FROM node:20-slim
|
| 37 |
-
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
|
|
|
|
| 38 |
|
| 39 |
WORKDIR /app
|
| 40 |
COPY --from=builder /app/.next/standalone ./
|
|
@@ -49,59 +44,89 @@ ENV INITIAL_PASSWORD=123456
|
|
| 49 |
ENV AUTH_COOKIE_SECURE=true
|
| 50 |
ENV DB_PATH=/root/.9router/db/data.sqlite
|
| 51 |
ENV HF_DATASET=gunnybd01/9router-db-backup
|
|
|
|
| 52 |
|
| 53 |
EXPOSE 7860
|
| 54 |
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
DATASET="${HF_DATASET:-gunnybd01/9router-db-backup}"
|
| 60 |
-
if [ -z "$TOKEN" ]; then echo "[sync] no HF_TOKEN, skip"; exit 0; fi
|
| 61 |
-
if [ ! -f "$DB_FILE" ]; then echo "[sync] no DB file, skip"; exit 0; fi
|
| 62 |
-
echo "[sync] Pushing DB at $(date)..."
|
| 63 |
-
HTTP=$(curl -s -o /tmp/sr.txt -w "%{http_code}" -X PUT -H "Authorization: Bearer $TOKEN" -T "$DB_FILE" "https://huggingface.co/api/datasets/${DATASET}/upload/main/data.sqlite")
|
| 64 |
-
echo "[sync] HTTP $HTTP: $(cat /tmp/sr.txt | head -c 100)"
|
| 65 |
-
SYNCEOF
|
| 66 |
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
TOKEN
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
|
| 90 |
RUN cat > /start.sh << 'STARTEOF'
|
| 91 |
#!/bin/sh
|
| 92 |
-
# 1. Restore DB from
|
| 93 |
-
|
| 94 |
-
# 2. Start
|
| 95 |
node /app/server.js &
|
| 96 |
APP_PID=$!
|
| 97 |
-
# 3.
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
|
|
|
| 101 |
# 5. Wait
|
| 102 |
wait $APP_PID
|
| 103 |
STARTEOF
|
| 104 |
|
| 105 |
-
RUN chmod +x /
|
| 106 |
-
|
| 107 |
CMD ["/bin/sh", "/start.sh"]
|
|
|
|
| 1 |
FROM node:20-slim AS builder
|
|
|
|
| 2 |
WORKDIR /app
|
| 3 |
RUN apt-get update && apt-get install -y git python3 make g++ && rm -rf /var/lib/apt/lists/*
|
| 4 |
RUN git clone --depth=1 https://github.com/decolua/9router.git .
|
|
|
|
| 6 |
RUN cat > next.config.mjs << 'NEXTEOF'
|
| 7 |
const nextConfig = {
|
| 8 |
output: "standalone",
|
| 9 |
+
serverExternalPackages: ["better-sqlite3","sql.js","node:sqlite","bun:sqlite"],
|
| 10 |
+
images:{unoptimized:true},env:{},
|
| 11 |
+
webpack:(config,{isServer})=>{
|
| 12 |
+
if(!isServer)config.resolve.fallback={...config.resolve.fallback,fs:false,path:false};
|
| 13 |
+
config.watchOptions={...config.watchOptions,ignored:/[\/](logs|\.next)[\/]/};
|
|
|
|
| 14 |
return config;
|
| 15 |
},
|
| 16 |
+
async headers(){return[{source:"/(.*)",headers:[{key:"X-Frame-Options",value:"ALLOWALL"},{key:"Content-Security-Policy",value:"frame-ancestors *"}]}];},
|
| 17 |
+
async rewrites(){return[
|
| 18 |
+
{source:"/v1/v1/:path*",destination:"/api/v1/:path*"},
|
| 19 |
+
{source:"/v1/v1",destination:"/api/v1"},
|
| 20 |
+
{source:"/codex/:path*",destination:"/api/v1/responses"},
|
| 21 |
+
{source:"/v1/:path*",destination:"/api/v1/:path*"},
|
| 22 |
+
{source:"/v1",destination:"/api/v1"}
|
| 23 |
+
];}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
};
|
| 25 |
export default nextConfig;
|
| 26 |
NEXTEOF
|
|
|
|
| 28 |
|
| 29 |
# ---- Runtime ----
|
| 30 |
FROM node:20-slim
|
| 31 |
+
RUN apt-get update && apt-get install -y python3 python3-pip curl && rm -rf /var/lib/apt/lists/*
|
| 32 |
+
RUN pip3 install huggingface_hub --break-system-packages --quiet
|
| 33 |
|
| 34 |
WORKDIR /app
|
| 35 |
COPY --from=builder /app/.next/standalone ./
|
|
|
|
| 44 |
ENV AUTH_COOKIE_SECURE=true
|
| 45 |
ENV DB_PATH=/root/.9router/db/data.sqlite
|
| 46 |
ENV HF_DATASET=gunnybd01/9router-db-backup
|
| 47 |
+
ENV SYNC_INTERVAL=3600
|
| 48 |
|
| 49 |
EXPOSE 7860
|
| 50 |
|
| 51 |
+
# Python script: push DB lên HF Dataset
|
| 52 |
+
RUN cat > /sync_db.py << 'PYEOF'
|
| 53 |
+
import os, sys, time
|
| 54 |
+
from huggingface_hub import HfApi
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
|
| 56 |
+
DB_FILE = os.environ.get("DB_PATH", "/root/.9router/db/data.sqlite")
|
| 57 |
+
TOKEN = os.environ.get("HF_TOKEN", "")
|
| 58 |
+
DATASET = os.environ.get("HF_DATASET", "gunnybd01/9router-db-backup")
|
| 59 |
+
|
| 60 |
+
if not TOKEN:
|
| 61 |
+
print("[sync] HF_TOKEN not set, skip"); sys.exit(0)
|
| 62 |
+
if not os.path.exists(DB_FILE):
|
| 63 |
+
print(f"[sync] DB not found: {DB_FILE}"); sys.exit(0)
|
| 64 |
+
|
| 65 |
+
sz = os.path.getsize(DB_FILE)
|
| 66 |
+
print(f"[sync] Pushing DB ({sz} bytes) -> {DATASET} ...")
|
| 67 |
+
try:
|
| 68 |
+
api = HfApi(token=TOKEN)
|
| 69 |
+
api.upload_file(
|
| 70 |
+
path_or_fileobj=DB_FILE,
|
| 71 |
+
path_in_repo="data.sqlite",
|
| 72 |
+
repo_id=DATASET,
|
| 73 |
+
repo_type="dataset",
|
| 74 |
+
commit_message=f"DB sync {time.strftime('%Y-%m-%d %H:%M')}",
|
| 75 |
+
)
|
| 76 |
+
print(f"[sync] OK at {time.strftime('%Y-%m-%d %H:%M:%S')}")
|
| 77 |
+
except Exception as e:
|
| 78 |
+
print(f"[sync] ERROR: {e}")
|
| 79 |
+
PYEOF
|
| 80 |
+
|
| 81 |
+
# Python script: pull DB từ HF Dataset khi startup
|
| 82 |
+
RUN cat > /restore_db.py << 'PYEOF2'
|
| 83 |
+
import os, sys
|
| 84 |
+
from huggingface_hub import hf_hub_download
|
| 85 |
+
|
| 86 |
+
DB_FILE = os.environ.get("DB_PATH", "/root/.9router/db/data.sqlite")
|
| 87 |
+
TOKEN = os.environ.get("HF_TOKEN", "")
|
| 88 |
+
DATASET = os.environ.get("HF_DATASET", "gunnybd01/9router-db-backup")
|
| 89 |
+
|
| 90 |
+
os.makedirs(os.path.dirname(DB_FILE), exist_ok=True)
|
| 91 |
+
|
| 92 |
+
if not TOKEN:
|
| 93 |
+
print("[restore] HF_TOKEN not set, starting fresh"); sys.exit(0)
|
| 94 |
+
|
| 95 |
+
print(f"[restore] Pulling DB from {DATASET}...")
|
| 96 |
+
try:
|
| 97 |
+
path = hf_hub_download(
|
| 98 |
+
repo_id=DATASET,
|
| 99 |
+
filename="data.sqlite",
|
| 100 |
+
repo_type="dataset",
|
| 101 |
+
token=TOKEN,
|
| 102 |
+
local_dir="/tmp/hf_restore",
|
| 103 |
+
)
|
| 104 |
+
sz = os.path.getsize(path)
|
| 105 |
+
if sz > 4096:
|
| 106 |
+
import shutil
|
| 107 |
+
shutil.copy2(path, DB_FILE)
|
| 108 |
+
print(f"[restore] OK - {sz} bytes restored from backup")
|
| 109 |
+
else:
|
| 110 |
+
print(f"[restore] Backup too small ({sz}b), starting fresh")
|
| 111 |
+
except Exception as e:
|
| 112 |
+
print(f"[restore] No backup yet ({e}), starting fresh")
|
| 113 |
+
PYEOF2
|
| 114 |
|
| 115 |
RUN cat > /start.sh << 'STARTEOF'
|
| 116 |
#!/bin/sh
|
| 117 |
+
# 1. Restore DB from backup
|
| 118 |
+
python3 /restore_db.py
|
| 119 |
+
# 2. Start Next.js
|
| 120 |
node /app/server.js &
|
| 121 |
APP_PID=$!
|
| 122 |
+
# 3. Sync loop (default 1h)
|
| 123 |
+
INTERVAL="${SYNC_INTERVAL:-3600}"
|
| 124 |
+
(while true; do sleep "$INTERVAL"; python3 /sync_db.py; done) &
|
| 125 |
+
# 4. Sync on SIGTERM (Space sleeping)
|
| 126 |
+
trap "echo "[trap] Syncing before sleep..."; python3 /sync_db.py; kill $APP_PID 2>/dev/null; exit 0" TERM INT
|
| 127 |
# 5. Wait
|
| 128 |
wait $APP_PID
|
| 129 |
STARTEOF
|
| 130 |
|
| 131 |
+
RUN chmod +x /start.sh
|
|
|
|
| 132 |
CMD ["/bin/sh", "/start.sh"]
|