Spaces:
Running
Running
Fix routing, ECONNREFUSED, and Cloudflare setup
Browse files- Move dashboard to /_status, proxy / root directly to Paperclip
(fixes "Company not found APP" β SPA no longer sees /app/ prefix)
- Hardcode PAPERCLIP_HOST to 127.0.0.1 instead of reading HOST env
(fixes ECONNREFUSED 0.0.0.0:3100 β 0.0.0.0 is bind-only)
- Remove CLOUDFLARE_ACCOUNT_ID requirement from setup condition
(setup script already auto-discovers account ID)
- Source CF proxy env file after setup so CLOUDFLARE_PROXY_URL/SECRET
reach the Node process
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- README.md +4 -4
- health-server.js +11 -35
- start.sh +10 -3
README.md
CHANGED
|
@@ -185,7 +185,7 @@ docker-compose up -d
|
|
| 185 |
|
| 186 |
### Dashboard
|
| 187 |
|
| 188 |
-
Access the health monitoring dashboard at: `http://your-space-url/`
|
| 189 |
|
| 190 |
**Shows:**
|
| 191 |
|
|
@@ -196,7 +196,7 @@ Access the health monitoring dashboard at: `http://your-space-url/`
|
|
| 196 |
|
| 197 |
### Paperclip UI
|
| 198 |
|
| 199 |
-
Full Paperclip interface at: `http://your-space-url/
|
| 200 |
|
| 201 |
**Features:**
|
| 202 |
|
|
@@ -277,7 +277,7 @@ python3 /app/paperclip-sync.py restore
|
|
| 277 |
|
| 278 |
### Paperclip Not Accessible
|
| 279 |
|
| 280 |
-
**Problem**: Can't reach <http://localhost:7861/
|
| 281 |
|
| 282 |
**Solution:**
|
| 283 |
|
|
@@ -345,7 +345,7 @@ python3 /app/paperclip-sync.py restore
|
|
| 345 |
|
| 346 |
```
|
| 347 |
βββββββββββββββββββ
|
| 348 |
-
β Paperclip UI β (http://space-url/
|
| 349 |
β & REST API β
|
| 350 |
ββββββββββ¬βββββββββ
|
| 351 |
β
|
|
|
|
| 185 |
|
| 186 |
### Dashboard
|
| 187 |
|
| 188 |
+
Access the health monitoring dashboard at: `http://your-space-url/_status`
|
| 189 |
|
| 190 |
**Shows:**
|
| 191 |
|
|
|
|
| 196 |
|
| 197 |
### Paperclip UI
|
| 198 |
|
| 199 |
+
Full Paperclip interface at: `http://your-space-url/`
|
| 200 |
|
| 201 |
**Features:**
|
| 202 |
|
|
|
|
| 277 |
|
| 278 |
### Paperclip Not Accessible
|
| 279 |
|
| 280 |
+
**Problem**: Can't reach <http://localhost:7861/>
|
| 281 |
|
| 282 |
**Solution:**
|
| 283 |
|
|
|
|
| 345 |
|
| 346 |
```
|
| 347 |
βββββββββββββββββββ
|
| 348 |
+
β Paperclip UI β (http://space-url/)
|
| 349 |
β & REST API β
|
| 350 |
ββββββββββ¬βββββββββ
|
| 351 |
β
|
health-server.js
CHANGED
|
@@ -9,7 +9,7 @@ const net = require("net");
|
|
| 9 |
|
| 10 |
const app = express();
|
| 11 |
const PORT = 7861; // always public-facing port, never read from PORT (that's for Paperclip)
|
| 12 |
-
const PAPERCLIP_HOST =
|
| 13 |
const PAPERCLIP_PORT = 3100;
|
| 14 |
|
| 15 |
// Middleware
|
|
@@ -84,14 +84,18 @@ app.get("/health", async (req, res) => {
|
|
| 84 |
// ============================================================================
|
| 85 |
// Dashboard Route
|
| 86 |
// ============================================================================
|
| 87 |
-
app.get("/", (req, res) => {
|
| 88 |
res.send(getDashboardHTML());
|
| 89 |
});
|
| 90 |
|
| 91 |
-
app.get("/
|
| 92 |
res.send(getDashboardHTML());
|
| 93 |
});
|
| 94 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
app.get("/dashboard/status", (req, res) => {
|
| 96 |
const syncStatus = readSyncStatus();
|
| 97 |
const uptime = process.uptime();
|
|
@@ -132,34 +136,6 @@ app.post("/dashboard/uptimerobot/setup", (req, res) => {
|
|
| 132 |
// Reverse Proxy Routes
|
| 133 |
// ============================================================================
|
| 134 |
|
| 135 |
-
// Proxy all /app/* requests to Paperclip
|
| 136 |
-
app.all("/app/*", async (req, res) => {
|
| 137 |
-
const targetPath = req.path.replace("/app", "") || "/";
|
| 138 |
-
const targetUrl = `http://${PAPERCLIP_HOST}:${PAPERCLIP_PORT}${targetPath}`;
|
| 139 |
-
|
| 140 |
-
try {
|
| 141 |
-
const response = await proxyRequest(
|
| 142 |
-
req.method,
|
| 143 |
-
targetUrl,
|
| 144 |
-
req.headers,
|
| 145 |
-
req.body,
|
| 146 |
-
);
|
| 147 |
-
|
| 148 |
-
// Copy response headers
|
| 149 |
-
Object.keys(response.headers).forEach((key) => {
|
| 150 |
-
res.setHeader(key, response.headers[key]);
|
| 151 |
-
});
|
| 152 |
-
|
| 153 |
-
res.status(response.statusCode).send(response.body);
|
| 154 |
-
} catch (error) {
|
| 155 |
-
console.error(`Proxy error: ${error.message}`);
|
| 156 |
-
res.status(503).json({
|
| 157 |
-
error: "Paperclip service unavailable",
|
| 158 |
-
details: error.message,
|
| 159 |
-
});
|
| 160 |
-
}
|
| 161 |
-
});
|
| 162 |
-
|
| 163 |
// Proxy all /api/* requests to Paperclip
|
| 164 |
app.all("/api/*", async (req, res) => {
|
| 165 |
const targetPath = req.path;
|
|
@@ -623,10 +599,10 @@ function getDashboardHTML() {
|
|
| 623 |
</div>
|
| 624 |
<div class="stat">
|
| 625 |
<span class="stat-label">UI URL</span>
|
| 626 |
-
<span class="stat-value"><span class="code">/
|
| 627 |
</div>
|
| 628 |
<div class="button-group">
|
| 629 |
-
<a href="/
|
| 630 |
</div>
|
| 631 |
</div>
|
| 632 |
|
|
@@ -684,7 +660,7 @@ function getDashboardHTML() {
|
|
| 684 |
<div class="card">
|
| 685 |
<h2>π Resources</h2>
|
| 686 |
<div class="button-group" style="flex-direction: column;">
|
| 687 |
-
<a href="/
|
| 688 |
<a href="/api/" class="button button-secondary" target="_blank">API Reference</a>
|
| 689 |
</div>
|
| 690 |
<div class="stat" style="margin-top: 16px;">
|
|
@@ -819,5 +795,5 @@ server.listen(PORT, "0.0.0.0", () => {
|
|
| 819 |
console.log(`β Health server listening on port ${PORT}`);
|
| 820 |
console.log(`β Dashboard: http://localhost:${PORT}/`);
|
| 821 |
console.log(`β API proxy: http://localhost:${PORT}/api/*`);
|
| 822 |
-
console.log(`β App proxy: http://localhost:${PORT}/
|
| 823 |
});
|
|
|
|
| 9 |
|
| 10 |
const app = express();
|
| 11 |
const PORT = 7861; // always public-facing port, never read from PORT (that's for Paperclip)
|
| 12 |
+
const PAPERCLIP_HOST = "127.0.0.1";
|
| 13 |
const PAPERCLIP_PORT = 3100;
|
| 14 |
|
| 15 |
// Middleware
|
|
|
|
| 84 |
// ============================================================================
|
| 85 |
// Dashboard Route
|
| 86 |
// ============================================================================
|
| 87 |
+
app.get("/_status", (req, res) => {
|
| 88 |
res.send(getDashboardHTML());
|
| 89 |
});
|
| 90 |
|
| 91 |
+
app.get("/_status/", (req, res) => {
|
| 92 |
res.send(getDashboardHTML());
|
| 93 |
});
|
| 94 |
|
| 95 |
+
app.get("/dashboard/", (req, res) => {
|
| 96 |
+
res.redirect("/_status");
|
| 97 |
+
});
|
| 98 |
+
|
| 99 |
app.get("/dashboard/status", (req, res) => {
|
| 100 |
const syncStatus = readSyncStatus();
|
| 101 |
const uptime = process.uptime();
|
|
|
|
| 136 |
// Reverse Proxy Routes
|
| 137 |
// ============================================================================
|
| 138 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 139 |
// Proxy all /api/* requests to Paperclip
|
| 140 |
app.all("/api/*", async (req, res) => {
|
| 141 |
const targetPath = req.path;
|
|
|
|
| 599 |
</div>
|
| 600 |
<div class="stat">
|
| 601 |
<span class="stat-label">UI URL</span>
|
| 602 |
+
<span class="stat-value"><span class="code">/</span></span>
|
| 603 |
</div>
|
| 604 |
<div class="button-group">
|
| 605 |
+
<a href="/" class="button button-primary" target="_blank">Open Paperclip UI</a>
|
| 606 |
</div>
|
| 607 |
</div>
|
| 608 |
|
|
|
|
| 660 |
<div class="card">
|
| 661 |
<h2>π Resources</h2>
|
| 662 |
<div class="button-group" style="flex-direction: column;">
|
| 663 |
+
<a href="/" class="button button-primary" target="_blank">Paperclip Dashboard</a>
|
| 664 |
<a href="/api/" class="button button-secondary" target="_blank">API Reference</a>
|
| 665 |
</div>
|
| 666 |
<div class="stat" style="margin-top: 16px;">
|
|
|
|
| 795 |
console.log(`β Health server listening on port ${PORT}`);
|
| 796 |
console.log(`β Dashboard: http://localhost:${PORT}/`);
|
| 797 |
console.log(`β API proxy: http://localhost:${PORT}/api/*`);
|
| 798 |
+
console.log(`β App proxy: http://localhost:${PORT}/ (root β Paperclip)`);
|
| 799 |
});
|
start.sh
CHANGED
|
@@ -112,11 +112,18 @@ else
|
|
| 112 |
fi
|
| 113 |
|
| 114 |
# ββ Cloudflare Proxy ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 115 |
-
if [ -n "${CLOUDFLARE_WORKERS_TOKEN:-}" ]
|
| 116 |
echo "Setting up Cloudflare proxy..."
|
| 117 |
python3 /app/cloudflare-proxy-setup.py 2>&1 || echo "Cloudflare setup failed, continuing without proxy"
|
| 118 |
fi
|
| 119 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
# ββ Load Cloudflare module if present βββββββββββββββββββββββββββββββββββββββββ
|
| 121 |
if [ -f /app/cloudflare-proxy.js ]; then
|
| 122 |
export NODE_OPTIONS="--require /app/cloudflare-proxy.js"
|
|
@@ -251,8 +258,8 @@ fi
|
|
| 251 |
|
| 252 |
echo "HuggingClip is ready!"
|
| 253 |
echo ""
|
| 254 |
-
echo " Health dashboard : http://localhost:7861/"
|
| 255 |
-
echo " Paperclip UI : http://localhost:7861/
|
| 256 |
echo " API : http://localhost:7861/api/"
|
| 257 |
echo ""
|
| 258 |
|
|
|
|
| 112 |
fi
|
| 113 |
|
| 114 |
# ββ Cloudflare Proxy ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 115 |
+
if [ -n "${CLOUDFLARE_WORKERS_TOKEN:-}" ]; then
|
| 116 |
echo "Setting up Cloudflare proxy..."
|
| 117 |
python3 /app/cloudflare-proxy-setup.py 2>&1 || echo "Cloudflare setup failed, continuing without proxy"
|
| 118 |
fi
|
| 119 |
|
| 120 |
+
# Source CF proxy env if the setup script wrote it (provides CLOUDFLARE_PROXY_URL + SECRET)
|
| 121 |
+
_CF_ENV="/tmp/huggingclaw-cloudflare-proxy.env"
|
| 122 |
+
if [ -f "${_CF_ENV}" ]; then
|
| 123 |
+
# shellcheck source=/dev/null
|
| 124 |
+
. "${_CF_ENV}"
|
| 125 |
+
fi
|
| 126 |
+
|
| 127 |
# ββ Load Cloudflare module if present βββββββββββββββββββββββββββββββββββββββββ
|
| 128 |
if [ -f /app/cloudflare-proxy.js ]; then
|
| 129 |
export NODE_OPTIONS="--require /app/cloudflare-proxy.js"
|
|
|
|
| 258 |
|
| 259 |
echo "HuggingClip is ready!"
|
| 260 |
echo ""
|
| 261 |
+
echo " Health dashboard : http://localhost:7861/_status"
|
| 262 |
+
echo " Paperclip UI : http://localhost:7861/"
|
| 263 |
echo " API : http://localhost:7861/api/"
|
| 264 |
echo ""
|
| 265 |
|