Spaces:
Running
Running
Update Dockerfile
Browse files- Dockerfile +49 -21
Dockerfile
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
FROM node:22-alpine
|
| 2 |
|
| 3 |
-
|
|
|
|
| 4 |
|
| 5 |
WORKDIR /app
|
| 6 |
RUN npm install -g omniroute
|
|
@@ -11,7 +12,7 @@ ENV NODE_ENV=production
|
|
| 11 |
|
| 12 |
EXPOSE 7860
|
| 13 |
|
| 14 |
-
# 下载 + 反向代理服务(监听 7860)
|
| 15 |
RUN cat > /app/download_server.js << 'EOF'
|
| 16 |
const http = require('http');
|
| 17 |
const fs = require('fs');
|
|
@@ -34,7 +35,6 @@ const server = http.createServer((req, res) => {
|
|
| 34 |
const url = new URL(req.url, `http://localhost:${PORT}`);
|
| 35 |
const route = url.pathname;
|
| 36 |
|
| 37 |
-
// ── 列出可下载文件 ──
|
| 38 |
if (route === '/list') {
|
| 39 |
const result = {};
|
| 40 |
for (const dir of ALLOWED_DIRS) {
|
|
@@ -50,7 +50,6 @@ const server = http.createServer((req, res) => {
|
|
| 50 |
return;
|
| 51 |
}
|
| 52 |
|
| 53 |
-
// ── 下载文件(无 token)──
|
| 54 |
if (route === '/download') {
|
| 55 |
const filename = url.searchParams.get('file') || '';
|
| 56 |
const fullPath = safeResolvePath(filename);
|
|
@@ -70,7 +69,7 @@ const server = http.createServer((req, res) => {
|
|
| 70 |
return;
|
| 71 |
}
|
| 72 |
|
| 73 |
-
//
|
| 74 |
const proxyReq = http.request(
|
| 75 |
{ hostname: '127.0.0.1', port: UPSTREAM_PORT, path: req.url, method: req.method, headers: req.headers },
|
| 76 |
proxyRes => { res.writeHead(proxyRes.statusCode, proxyRes.headers); proxyRes.pipe(res); }
|
|
@@ -87,38 +86,67 @@ server.listen(PORT, '0.0.0.0', () => {
|
|
| 87 |
});
|
| 88 |
EOF
|
| 89 |
|
| 90 |
-
# 启动脚本
|
| 91 |
RUN cat > /app/entrypoint.sh << 'EOF'
|
| 92 |
#!/bin/sh
|
| 93 |
set -u
|
| 94 |
|
| 95 |
-
mkdir -p /root/.omniroute /data
|
| 96 |
|
| 97 |
-
# ──
|
| 98 |
-
if [ -
|
| 99 |
-
|
|
|
|
| 100 |
else
|
| 101 |
-
echo "⚠️
|
| 102 |
fi
|
| 103 |
-
|
| 104 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 105 |
else
|
| 106 |
-
echo "⚠️
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
fi
|
| 108 |
|
| 109 |
-
# ── 每 60 秒
|
| 110 |
(while true; do
|
| 111 |
sleep 60
|
| 112 |
if [ -f /root/.omniroute/storage.sqlite ]; then
|
| 113 |
-
if sqlite3 /root/.omniroute/storage.sqlite ".backup '/data/omni_storage.sqlite
|
| 114 |
-
|
| 115 |
-
|
|
|
|
|
|
|
|
|
|
| 116 |
fi
|
| 117 |
fi
|
| 118 |
if [ -f /root/.omniroute/settings.json ]; then
|
| 119 |
-
cp /root/.omniroute/settings.json /data/omni_settings.json
|
| 120 |
-
|
| 121 |
-
|
|
|
|
|
|
|
| 122 |
fi
|
| 123 |
done) &
|
| 124 |
|
|
|
|
| 1 |
FROM node:22-alpine
|
| 2 |
|
| 3 |
+
# sqlite: 一致性备份用;rclone: 连接 Google Drive
|
| 4 |
+
RUN apk add --no-cache sqlite rclone
|
| 5 |
|
| 6 |
WORKDIR /app
|
| 7 |
RUN npm install -g omniroute
|
|
|
|
| 12 |
|
| 13 |
EXPOSE 7860
|
| 14 |
|
| 15 |
+
# ───────── 下载 + 反向代理服务(监听 7860)─────────
|
| 16 |
RUN cat > /app/download_server.js << 'EOF'
|
| 17 |
const http = require('http');
|
| 18 |
const fs = require('fs');
|
|
|
|
| 35 |
const url = new URL(req.url, `http://localhost:${PORT}`);
|
| 36 |
const route = url.pathname;
|
| 37 |
|
|
|
|
| 38 |
if (route === '/list') {
|
| 39 |
const result = {};
|
| 40 |
for (const dir of ALLOWED_DIRS) {
|
|
|
|
| 50 |
return;
|
| 51 |
}
|
| 52 |
|
|
|
|
| 53 |
if (route === '/download') {
|
| 54 |
const filename = url.searchParams.get('file') || '';
|
| 55 |
const fullPath = safeResolvePath(filename);
|
|
|
|
| 69 |
return;
|
| 70 |
}
|
| 71 |
|
| 72 |
+
// 其余请求反向代理给 omniroute (8860)
|
| 73 |
const proxyReq = http.request(
|
| 74 |
{ hostname: '127.0.0.1', port: UPSTREAM_PORT, path: req.url, method: req.method, headers: req.headers },
|
| 75 |
proxyRes => { res.writeHead(proxyRes.statusCode, proxyRes.headers); proxyRes.pipe(res); }
|
|
|
|
| 86 |
});
|
| 87 |
EOF
|
| 88 |
|
| 89 |
+
# ───────── 启动脚本 ─────────
|
| 90 |
RUN cat > /app/entrypoint.sh << 'EOF'
|
| 91 |
#!/bin/sh
|
| 92 |
set -u
|
| 93 |
|
| 94 |
+
mkdir -p /root/.omniroute /data /root/.config/rclone
|
| 95 |
|
| 96 |
+
# ── 写入 rclone 配置(来自 HF Secret: RCLONE_CONF)──
|
| 97 |
+
if [ -n "${RCLONE_CONF:-}" ]; then
|
| 98 |
+
printf '%s\n' "$RCLONE_CONF" > /root/.config/rclone/rclone.conf
|
| 99 |
+
echo "✅ 已写入 rclone 配置"
|
| 100 |
else
|
| 101 |
+
echo "⚠️ 未设置 RCLONE_CONF,Google Drive 备份将不可用"
|
| 102 |
fi
|
| 103 |
+
|
| 104 |
+
# ── 固定加密 key(来自 HF Secret: STORAGE_ENCRYPTION_KEY)──
|
| 105 |
+
# 不固定的话,重启会生成新 key,导致恢复的旧库无法解密!
|
| 106 |
+
if [ -n "${STORAGE_ENCRYPTION_KEY:-}" ]; then
|
| 107 |
+
echo "STORAGE_ENCRYPTION_KEY=$STORAGE_ENCRYPTION_KEY" > /root/.omniroute/.env
|
| 108 |
+
echo "✅ 已写入固定 STORAGE_ENCRYPTION_KEY"
|
| 109 |
else
|
| 110 |
+
echo "⚠️ 未设置 STORAGE_ENCRYPTION_KEY,重启后恢复的库可能解不开!"
|
| 111 |
+
fi
|
| 112 |
+
|
| 113 |
+
# Google Drive 备份目录:远程名 om,文件夹 om-backup
|
| 114 |
+
GD_REMOTE="om:om-backup"
|
| 115 |
+
|
| 116 |
+
# ── 开机:从 Google Drive 拉取备份覆盖恢复 ──
|
| 117 |
+
if [ -n "${RCLONE_CONF:-}" ]; then
|
| 118 |
+
if rclone copyto "$GD_REMOTE/omni_storage.sqlite" /root/.omniroute/storage.sqlite --no-traverse 2>/dev/null; then
|
| 119 |
+
echo "✅ 从 GDrive 恢复 storage.sqlite"
|
| 120 |
+
# 恢复后清掉残留 WAL,避免脏数据覆盖
|
| 121 |
+
rm -f /root/.omniroute/storage.sqlite-wal /root/.omniroute/storage.sqlite-shm
|
| 122 |
+
else
|
| 123 |
+
echo "⚠️ GDrive 无 storage 备份,跳过恢复"
|
| 124 |
+
fi
|
| 125 |
+
if rclone copyto "$GD_REMOTE/omni_settings.json" /root/.omniroute/settings.json --no-traverse 2>/dev/null; then
|
| 126 |
+
echo "✅ 从 GDrive 恢复 settings.json"
|
| 127 |
+
else
|
| 128 |
+
echo "⚠️ GDrive 无 settings 备份,跳过恢复"
|
| 129 |
+
fi
|
| 130 |
fi
|
| 131 |
|
| 132 |
+
# ── 每 60 秒:一致性快照 + 覆盖上传到 Google Drive ──
|
| 133 |
(while true; do
|
| 134 |
sleep 60
|
| 135 |
if [ -f /root/.omniroute/storage.sqlite ]; then
|
| 136 |
+
if sqlite3 /root/.omniroute/storage.sqlite ".backup '/data/omni_storage.sqlite'" 2>/dev/null; then
|
| 137 |
+
if [ -n "${RCLONE_CONF:-}" ]; then
|
| 138 |
+
rclone copyto /data/omni_storage.sqlite "$GD_REMOTE/omni_storage.sqlite" 2>/dev/null \
|
| 139 |
+
&& echo "💾 [backup] storage.sqlite → GDrive(覆盖)" \
|
| 140 |
+
|| echo "⚠️ [backup] GDrive 上传失败"
|
| 141 |
+
fi
|
| 142 |
fi
|
| 143 |
fi
|
| 144 |
if [ -f /root/.omniroute/settings.json ]; then
|
| 145 |
+
cp /root/.omniroute/settings.json /data/omni_settings.json
|
| 146 |
+
if [ -n "${RCLONE_CONF:-}" ]; then
|
| 147 |
+
rclone copyto /data/omni_settings.json "$GD_REMOTE/omni_settings.json" 2>/dev/null \
|
| 148 |
+
&& echo "💾 [backup] settings.json → GDrive(覆盖)"
|
| 149 |
+
fi
|
| 150 |
fi
|
| 151 |
done) &
|
| 152 |
|