Update Dockerfile
Browse files- Dockerfile +33 -76
Dockerfile
CHANGED
|
@@ -10,15 +10,12 @@ const nextConfig = {
|
|
| 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 |
};
|
|
@@ -28,105 +25,65 @@ RUN npm install && npm run build
|
|
| 28 |
|
| 29 |
# ---- Runtime ----
|
| 30 |
FROM node:20-slim
|
| 31 |
-
RUN apt-get update && apt-get install -y python3 python3-pip
|
| 32 |
RUN pip3 install huggingface_hub --break-system-packages --quiet
|
| 33 |
-
|
| 34 |
WORKDIR /app
|
| 35 |
COPY --from=builder /app/.next/standalone ./
|
| 36 |
COPY --from=builder /app/.next/static ./.next/static
|
| 37 |
COPY --from=builder /app/public ./public
|
| 38 |
COPY --from=builder /app/open-sse ./open-sse
|
| 39 |
-
|
| 40 |
-
ENV PORT=7860
|
| 41 |
-
ENV HOSTNAME=0.0.0.0
|
| 42 |
ENV NEXT_PUBLIC_BASE_URL=https://gunnybd01-9router.hf.space
|
| 43 |
-
ENV INITIAL_PASSWORD=123456
|
| 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,
|
| 54 |
from huggingface_hub import HfApi
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 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 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 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,
|
| 84 |
from huggingface_hub import hf_hub_download
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 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 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 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 |
-
|
| 125 |
-
|
| 126 |
-
trap
|
| 127 |
-
# 5. Wait
|
| 128 |
wait $APP_PID
|
| 129 |
STARTEOF
|
| 130 |
-
|
| 131 |
RUN chmod +x /start.sh
|
| 132 |
CMD ["/bin/sh", "/start.sh"]
|
|
|
|
| 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)[\/]/};return config;
|
|
|
|
| 14 |
},
|
| 15 |
async headers(){return[{source:"/(.*)",headers:[{key:"X-Frame-Options",value:"ALLOWALL"},{key:"Content-Security-Policy",value:"frame-ancestors *"}]}];},
|
| 16 |
async rewrites(){return[
|
| 17 |
+
{source:"/v1/v1/:path*",destination:"/api/v1/:path*"},{source:"/v1/v1",destination:"/api/v1"},
|
| 18 |
+
{source:"/codex/:path*",destination:"/api/v1/responses"},{source:"/v1/:path*",destination:"/api/v1/:path*"},
|
|
|
|
|
|
|
| 19 |
{source:"/v1",destination:"/api/v1"}
|
| 20 |
];}
|
| 21 |
};
|
|
|
|
| 25 |
|
| 26 |
# ---- Runtime ----
|
| 27 |
FROM node:20-slim
|
| 28 |
+
RUN apt-get update && apt-get install -y python3 python3-pip && rm -rf /var/lib/apt/lists/*
|
| 29 |
RUN pip3 install huggingface_hub --break-system-packages --quiet
|
|
|
|
| 30 |
WORKDIR /app
|
| 31 |
COPY --from=builder /app/.next/standalone ./
|
| 32 |
COPY --from=builder /app/.next/static ./.next/static
|
| 33 |
COPY --from=builder /app/public ./public
|
| 34 |
COPY --from=builder /app/open-sse ./open-sse
|
| 35 |
+
ENV PORT=7860 HOSTNAME=0.0.0.0
|
|
|
|
|
|
|
| 36 |
ENV NEXT_PUBLIC_BASE_URL=https://gunnybd01-9router.hf.space
|
| 37 |
+
ENV INITIAL_PASSWORD=123456 AUTH_COOKIE_SECURE=true
|
|
|
|
| 38 |
ENV DB_PATH=/root/.9router/db/data.sqlite
|
| 39 |
ENV HF_DATASET=gunnybd01/9router-db-backup
|
| 40 |
ENV SYNC_INTERVAL=3600
|
|
|
|
| 41 |
EXPOSE 7860
|
| 42 |
|
|
|
|
| 43 |
RUN cat > /sync_db.py << 'PYEOF'
|
| 44 |
+
import os,sys,time
|
| 45 |
from huggingface_hub import HfApi
|
| 46 |
+
db=os.environ.get("DB_PATH","/root/.9router/db/data.sqlite")
|
| 47 |
+
tok=os.environ.get("HF_TOKEN",""); ds=os.environ.get("HF_DATASET","gunnybd01/9router-db-backup")
|
| 48 |
+
if not tok: print("[sync] no HF_TOKEN"); sys.exit(0)
|
| 49 |
+
if not os.path.exists(db): print("[sync] no DB"); sys.exit(0)
|
| 50 |
+
print(f"[sync] {os.path.getsize(db)}b -> {ds} @ {time.strftime('%H:%M:%S')}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
try:
|
| 52 |
+
HfApi(token=tok).upload_file(path_or_fileobj=db,path_in_repo="data.sqlite",
|
| 53 |
+
repo_id=ds,repo_type="dataset",commit_message=f"backup {time.strftime('%Y-%m-%d %H:%M')}")
|
| 54 |
+
print("[sync] OK")
|
| 55 |
+
except Exception as e: print(f"[sync] ERR: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
PYEOF
|
| 57 |
|
|
|
|
| 58 |
RUN cat > /restore_db.py << 'PYEOF2'
|
| 59 |
+
import os,sys,shutil
|
| 60 |
from huggingface_hub import hf_hub_download
|
| 61 |
+
db=os.environ.get("DB_PATH","/root/.9router/db/data.sqlite")
|
| 62 |
+
tok=os.environ.get("HF_TOKEN",""); ds=os.environ.get("HF_DATASET","gunnybd01/9router-db-backup")
|
| 63 |
+
os.makedirs(os.path.dirname(db),exist_ok=True)
|
| 64 |
+
if not tok: print("[restore] no HF_TOKEN"); sys.exit(0)
|
| 65 |
+
print(f"[restore] Pulling from {ds}...")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
try:
|
| 67 |
+
dl=hf_hub_download(repo_id=ds,filename="data.sqlite",repo_type="dataset",token=tok,local_dir="/tmp/hfr")
|
| 68 |
+
sz=os.path.getsize(dl)
|
| 69 |
+
if sz>4096: shutil.copy2(dl,db); print(f"[restore] OK {sz}b")
|
| 70 |
+
else: print(f"[restore] too small {sz}b, fresh")
|
| 71 |
+
except Exception as e: print(f"[restore] no backup: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
PYEOF2
|
| 73 |
|
| 74 |
+
# Wrapper script cho trap (tranh sh quoting issues)
|
| 75 |
+
RUN printf '#!/bin/sh\npython3 /sync_db.py\n' > /do_sync.sh && chmod +x /do_sync.sh
|
| 76 |
+
|
| 77 |
RUN cat > /start.sh << 'STARTEOF'
|
| 78 |
#!/bin/sh
|
|
|
|
| 79 |
python3 /restore_db.py
|
|
|
|
| 80 |
node /app/server.js &
|
| 81 |
APP_PID=$!
|
|
|
|
| 82 |
INTERVAL="${SYNC_INTERVAL:-3600}"
|
| 83 |
+
echo "[start] Sync every ${INTERVAL}s, PID=$$"
|
| 84 |
+
(while true; do sleep "$INTERVAL"; /do_sync.sh; done) &
|
| 85 |
+
trap /do_sync.sh TERM INT
|
|
|
|
| 86 |
wait $APP_PID
|
| 87 |
STARTEOF
|
|
|
|
| 88 |
RUN chmod +x /start.sh
|
| 89 |
CMD ["/bin/sh", "/start.sh"]
|