mirror of
https://github.com/mauricioabh/arbpulse.git
synced 2026-08-16 00:28:06 +00:00
Merge pull request #23 from mauricioabh/dev
feat(deploy): run behind existing host nginx (Caddy opt-in)
This commit is contained in:
+56
-47
@@ -1,80 +1,89 @@
|
|||||||
# Deploy en VPS (Hetzner) — Arb Pulse
|
# Deploy en VPS (Hetzner) — Arb Pulse
|
||||||
|
|
||||||
Despliegue con Docker Compose: el contenedor `app` (Node + tsx) detrás de
|
Despliegue con Docker Compose para correr 24/7 desde la rama `main`. El contenedor
|
||||||
`caddy`, que emite HTTPS automáticamente (Let's Encrypt). Pensado para correr
|
`app` (Node + tsx) queda en `127.0.0.1:8080` y un **reverse proxy del host** expone
|
||||||
24/7 desde la rama `main`.
|
HTTPS. Dos modos:
|
||||||
|
|
||||||
|
- **Opción A — detrás de nginx existente (recomendado en este VPS).** El servidor ya
|
||||||
|
corre nginx en 80/443 con certbot para otras apps (p. ej. `consumet.wayool.com`,
|
||||||
|
`openclaw.wayool.com`). Se agrega un vhost para `arbpulse.wayool.com` y punto.
|
||||||
|
- **Opción B — Caddy bundleado.** Solo para un server **fresco** sin nada en 80/443.
|
||||||
|
|
||||||
## Prerrequisitos
|
## Prerrequisitos
|
||||||
|
|
||||||
1. VPS Ubuntu/Debian (recomendado 2 vCPU / 2 GB RAM — p. ej. Hetzner CX22).
|
1. VPS Ubuntu/Debian (recomendado 2 vCPU / 2 GB RAM — p. ej. Hetzner CX22).
|
||||||
2. Subdominio en Cloudflare (zona `wayool.com`): `arbpulse.wayool.com` con un
|
2. Subdominio `arbpulse.wayool.com` con registro **A → IP del VPS** (ya creado en
|
||||||
registro **A → IP del VPS**. Ver "DNS en Cloudflare" abajo.
|
Cloudflare, ver abajo).
|
||||||
3. Puertos abiertos:
|
3. Docker + plugin compose (el `deploy.sh` los instala si faltan).
|
||||||
```bash
|
|
||||||
sudo ufw allow 22 && sudo ufw allow 80 && sudo ufw allow 443 && sudo ufw --force enable
|
|
||||||
```
|
|
||||||
|
|
||||||
## DNS en Cloudflare (zona wayool.com)
|
## DNS en Cloudflare (zona wayool.com)
|
||||||
|
|
||||||
El dominio `wayool.com` está gestionado por Cloudflare. La app se sirve en el
|
- Registro **A**, nombre `arbpulse`, contenido = IP del VPS, **"DNS only" (nube gris)**.
|
||||||
subdominio **`arbpulse.wayool.com`**.
|
- Motivo: certbot/Caddy emiten el cert vía HTTP-01 (reto directo al origen) y el
|
||||||
|
SSE de `/api/stream` fluye sin buffering del proxy de Cloudflare.
|
||||||
|
- Verificar: `dig +short arbpulse.wayool.com` debe devolver la IP del VPS.
|
||||||
|
|
||||||
- Registro: **A**, nombre `arbpulse`, contenido = IP pública del VPS.
|
---
|
||||||
- **Proxy: "DNS only" (nube gris), NO proxied (nube naranja).**
|
|
||||||
- Motivo: Caddy emite el cert Let's Encrypt vía HTTP-01 (requiere que el reto en
|
|
||||||
el puerto 80 llegue directo al origen), y el stream SSE de `/api/stream` fluye
|
|
||||||
sin el buffering/timeout del proxy de Cloudflare.
|
|
||||||
- Si más adelante querés proxear con Cloudflare (naranja) para ocultar la IP,
|
|
||||||
hay que cambiar Caddy a challenge DNS-01 (plugin `caddy-dns/cloudflare` + token
|
|
||||||
de API) y poner SSL/TLS en "Full (strict)". No es necesario para arrancar.
|
|
||||||
- Verificar propagación: `dig +short arbpulse.wayool.com` debe devolver la IP del
|
|
||||||
VPS antes de que Caddy pida el certificado.
|
|
||||||
|
|
||||||
## Deploy (para el agente del VPS)
|
## Opción A — detrás del nginx existente (recomendado)
|
||||||
|
|
||||||
Todo lo hace el script idempotente `deploy.sh` (instala Docker si falta, clona o
|
No toca tus otras apps ni Caddy. Solo levanta el contenedor `app` en loopback y le
|
||||||
actualiza el repo, y levanta los contenedores). Es seguro re-ejecutarlo.
|
pone un vhost de nginx con certbot (mismo patrón que consumet/openclaw).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1) Traer el script y ejecutarlo (primera vez: crea .env y se detiene)
|
# 1) Traer y correr el script (1ra vez: crea .env y se detiene). App-only por default.
|
||||||
curl -fsSL https://raw.githubusercontent.com/mauricioabh/arbpulse/main/deploy/deploy.sh -o /tmp/arbpulse-deploy.sh
|
curl -fsSL https://raw.githubusercontent.com/mauricioabh/arbpulse/main/deploy/deploy.sh -o /tmp/arbpulse-deploy.sh
|
||||||
bash /tmp/arbpulse-deploy.sh
|
bash /tmp/arbpulse-deploy.sh
|
||||||
|
|
||||||
# 2) Editar el .env con el dominio y secretos
|
# 2) Editar el .env (DOMAIN + secretos opcionales)
|
||||||
nano /opt/arbpulse/deploy/.env # DOMAIN=... ; SENTRY_DSN=... (opcional) ; UPSTASH_* (opcional)
|
nano /opt/arbpulse/deploy/.env # DOMAIN=arbpulse.wayool.com ; SENTRY_TRACING=false ; ...
|
||||||
|
|
||||||
# 3) Volver a ejecutar para construir y arrancar
|
# 3) Volver a correr: build + up del contenedor app (127.0.0.1:8080)
|
||||||
bash /tmp/arbpulse-deploy.sh
|
bash /tmp/arbpulse-deploy.sh
|
||||||
|
|
||||||
|
# 4) Instalar el vhost de nginx y emitir el cert
|
||||||
|
sudo cp /opt/arbpulse/deploy/nginx/arbpulse.wayool.com.conf /etc/nginx/sites-available/arbpulse.wayool.com
|
||||||
|
sudo ln -s /etc/nginx/sites-available/arbpulse.wayool.com /etc/nginx/sites-enabled/
|
||||||
|
sudo nginx -t && sudo systemctl reload nginx
|
||||||
|
sudo certbot --nginx -d arbpulse.wayool.com
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternativa (si ya está clonado el repo en `/opt/arbpulse`):
|
El vhost (`deploy/nginx/arbpulse.wayool.com.conf`) trae `proxy_buffering off` y
|
||||||
|
timeouts largos para que el SSE funcione. certbot copia el bloque `location` al
|
||||||
|
server TLS que genera, así que los ajustes SSE se mantienen en HTTPS.
|
||||||
|
|
||||||
|
## Opción B — Caddy bundleado (server fresco, sin nginx)
|
||||||
|
|
||||||
|
Solo si nada más usa 80/443:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /opt/arbpulse/deploy
|
cd /opt/arbpulse/deploy
|
||||||
cp .env.vps.example .env && nano .env # solo la primera vez
|
cp .env.vps.example .env && nano .env # DOMAIN=arbpulse.wayool.com ...
|
||||||
docker compose up -d --build
|
WITH_CADDY=1 bash /tmp/arbpulse-deploy.sh # o: docker compose --profile caddy up -d --build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Verificar
|
## Verificar
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose -f /opt/arbpulse/deploy/docker-compose.yml ps
|
docker compose -f /opt/arbpulse/deploy/docker-compose.yml ps # app healthy/running
|
||||||
curl -s http://127.0.0.1:8080/api/health # local
|
curl -s http://127.0.0.1:8080/api/health # local
|
||||||
curl -s https://TU_DOMINIO/api/health # público (tras propagar DNS)
|
curl -s https://arbpulse.wayool.com/api/health # público (HTTPS)
|
||||||
```
|
```
|
||||||
|
|
||||||
Dashboard: `https://TU_DOMINIO` → badge **LIVE** y los 4 exchanges en la matriz.
|
Dashboard: `https://arbpulse.wayool.com` → badge **LIVE** y los 4 exchanges.
|
||||||
|
|
||||||
## Variables de entorno
|
## Variables de entorno
|
||||||
|
|
||||||
Ver `.env.vps.example`. Claves:
|
Ver `.env.vps.example`. Claves:
|
||||||
|
|
||||||
- `DOMAIN` — dominio para Caddy/HTTPS (obligatorio).
|
- `DOMAIN` — `arbpulse.wayool.com` (usado por Caddy en Opción B; informativo en A).
|
||||||
- `SENTRY_DSN` — opcional; activa error monitoring.
|
- `SENTRY_DSN` — opcional; activa error monitoring.
|
||||||
- `SENTRY_TRACING` — dejar en `false` (default) para no consumir la cuota
|
- `SENTRY_TRACING` — dejar en `false` (default) para no consumir la cuota free-tier
|
||||||
free-tier de spans en operación 24/7.
|
de spans en operación 24/7.
|
||||||
- `UPSTASH_REDIS_REST_URL` / `UPSTASH_REDIS_REST_TOKEN` — opcionales (rate limit
|
- `UPSTASH_REDIS_REST_URL` / `UPSTASH_REDIS_REST_TOKEN` — opcionales (rate limit +
|
||||||
+ cache). Vacío = desactivado.
|
cache). Vacío = desactivado.
|
||||||
|
|
||||||
> Nunca comitees el `.env` real. Solo `.env.vps.example` vive en el repo.
|
> Nunca comitees el `.env` real. Solo `.env.vps.example` vive en el repo.
|
||||||
|
|
||||||
@@ -84,15 +93,15 @@ Ver `.env.vps.example`. Claves:
|
|||||||
cd /opt/arbpulse/deploy
|
cd /opt/arbpulse/deploy
|
||||||
docker compose logs -f app # logs de la app
|
docker compose logs -f app # logs de la app
|
||||||
docker compose restart app # reiniciar
|
docker compose restart app # reiniciar
|
||||||
docker compose down # detener
|
docker compose down # detener (app; agrega --profile caddy si aplica)
|
||||||
bash /tmp/arbpulse-deploy.sh # actualizar (git pull main + rebuild)
|
bash /tmp/arbpulse-deploy.sh # actualizar (git pull main + rebuild)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Notas
|
## Notas
|
||||||
|
|
||||||
- Caddy usa `flush_interval -1` para que el SSE (`/api/stream`) fluya en tiempo
|
- El puerto 8080 se publica solo en `127.0.0.1` (no expuesto a Internet); el tráfico
|
||||||
real; no comprimir `text/event-stream`.
|
público entra por el reverse proxy del host (nginx o Caddy).
|
||||||
- El puerto 8080 se publica solo en `127.0.0.1` (no expuesto a Internet); el
|
- La app ya envía `X-Accel-Buffering: no` en el SSE, que nginx respeta para no
|
||||||
tráfico público entra por Caddy (80/443).
|
bufferear ese response.
|
||||||
- Región: Hetzner no tiene Asia; para menor latencia a Binance/Bybit/OKX evalúa
|
- Región: Hetzner no tiene Asia; para menor latencia a Binance/Bybit/OKX evalúa un
|
||||||
un VPS en Singapur. Para Kraken (EU) Falkenstein/Helsinki va bien.
|
VPS en Singapur. Para Kraken (EU) Falkenstein/Helsinki va bien.
|
||||||
|
|||||||
+20
-4
@@ -3,11 +3,16 @@
|
|||||||
# Safe to re-run: installs Docker if missing, clones or fast-forwards the repo,
|
# Safe to re-run: installs Docker if missing, clones or fast-forwards the repo,
|
||||||
# then (re)builds and restarts the containers. On first run it creates .env from
|
# then (re)builds and restarts the containers. On first run it creates .env from
|
||||||
# the example and stops so you can fill in DOMAIN + secrets.
|
# the example and stops so you can fill in DOMAIN + secrets.
|
||||||
|
#
|
||||||
|
# Default: runs ONLY the app on 127.0.0.1:8080 (put it behind your host reverse
|
||||||
|
# proxy — see deploy/nginx/). Set WITH_CADDY=1 to also start the bundled Caddy on
|
||||||
|
# 80/443 (only for a fresh server with nothing else on those ports).
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
REPO_URL="${REPO_URL:-https://github.com/mauricioabh/arbpulse.git}"
|
REPO_URL="${REPO_URL:-https://github.com/mauricioabh/arbpulse.git}"
|
||||||
APP_DIR="${APP_DIR:-/opt/arbpulse}"
|
APP_DIR="${APP_DIR:-/opt/arbpulse}"
|
||||||
BRANCH="${BRANCH:-main}"
|
BRANCH="${BRANCH:-main}"
|
||||||
|
WITH_CADDY="${WITH_CADDY:-0}"
|
||||||
|
|
||||||
echo "==> Arb Pulse VPS deploy (branch: $BRANCH, dir: $APP_DIR)"
|
echo "==> Arb Pulse VPS deploy (branch: $BRANCH, dir: $APP_DIR)"
|
||||||
|
|
||||||
@@ -48,8 +53,13 @@ if [ ! -f .env ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# 4) Build + run
|
# 4) Build + run
|
||||||
echo "==> Building and starting containers..."
|
if [ "$WITH_CADDY" = "1" ]; then
|
||||||
docker compose up -d --build
|
echo "==> Building and starting app + bundled Caddy (ports 80/443)..."
|
||||||
|
docker compose --profile caddy up -d --build
|
||||||
|
else
|
||||||
|
echo "==> Building and starting app only (127.0.0.1:8080)..."
|
||||||
|
docker compose up -d --build
|
||||||
|
fi
|
||||||
|
|
||||||
echo "==> Waiting for health..."
|
echo "==> Waiting for health..."
|
||||||
sleep 8
|
sleep 8
|
||||||
@@ -60,5 +70,11 @@ if curl -fsS http://127.0.0.1:8080/api/health >/dev/null 2>&1; then
|
|||||||
else
|
else
|
||||||
echo "!! Health check not passing yet. Inspect: docker compose logs -f app"
|
echo "!! Health check not passing yet. Inspect: docker compose logs -f app"
|
||||||
fi
|
fi
|
||||||
echo "==> If your domain's A record points here, Caddy will issue HTTPS automatically."
|
|
||||||
echo "==> Verify: curl -s https://\$DOMAIN/api/health"
|
if [ "$WITH_CADDY" = "1" ]; then
|
||||||
|
echo "==> Bundled Caddy will issue HTTPS once DNS for \$DOMAIN points here."
|
||||||
|
echo "==> Verify: curl -s https://\$DOMAIN/api/health"
|
||||||
|
else
|
||||||
|
echo "==> App is bound to 127.0.0.1:8080. Put it behind your host reverse proxy:"
|
||||||
|
echo " see $APP_DIR/deploy/nginx/arbpulse.wayool.com.conf (nginx + certbot)."
|
||||||
|
fi
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
# Arb Pulse — VPS deployment (app + Caddy reverse proxy with automatic HTTPS).
|
# Arb Pulse — VPS deployment.
|
||||||
# Usage: from this directory, `docker compose up -d --build`.
|
#
|
||||||
|
# Default (`docker compose up -d --build`): runs ONLY the app container, bound to
|
||||||
|
# 127.0.0.1:8080. Put it behind your existing reverse proxy (nginx/Caddy/Traefik)
|
||||||
|
# on the host — see deploy/nginx/arbpulse.wayool.com.conf. This is the right mode
|
||||||
|
# when the host already owns ports 80/443 for other apps.
|
||||||
|
#
|
||||||
|
# Optional bundled Caddy (`docker compose --profile caddy up -d --build`): only for
|
||||||
|
# a FRESH server with nothing else on 80/443; Caddy then handles automatic HTTPS.
|
||||||
|
#
|
||||||
# Requires a ./.env file (copy from .env.vps.example and fill DOMAIN + secrets).
|
# Requires a ./.env file (copy from .env.vps.example and fill DOMAIN + secrets).
|
||||||
|
|
||||||
services:
|
services:
|
||||||
@@ -12,7 +20,7 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file:
|
env_file:
|
||||||
- ./.env
|
- ./.env
|
||||||
# Bind to loopback only; public traffic goes through Caddy on 80/443.
|
# Bind to loopback only; the host reverse proxy forwards public traffic here.
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:8080:8080"
|
- "127.0.0.1:8080:8080"
|
||||||
healthcheck:
|
healthcheck:
|
||||||
@@ -22,10 +30,13 @@ services:
|
|||||||
retries: 3
|
retries: 3
|
||||||
start_period: 15s
|
start_period: 15s
|
||||||
|
|
||||||
|
# Opt-in only via `--profile caddy`. Do NOT enable if the host already runs
|
||||||
|
# nginx/another proxy on 80/443 — the ports would collide.
|
||||||
caddy:
|
caddy:
|
||||||
image: caddy:2-alpine
|
image: caddy:2-alpine
|
||||||
container_name: arbpulse-caddy
|
container_name: arbpulse-caddy
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
profiles: ["caddy"]
|
||||||
depends_on:
|
depends_on:
|
||||||
- app
|
- app
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Arb Pulse — nginx vhost (host-level), to sit alongside consumet/openclaw.
|
||||||
|
#
|
||||||
|
# Install:
|
||||||
|
# sudo cp deploy/nginx/arbpulse.wayool.com.conf /etc/nginx/sites-available/arbpulse.wayool.com
|
||||||
|
# sudo ln -s /etc/nginx/sites-available/arbpulse.wayool.com /etc/nginx/sites-enabled/
|
||||||
|
# sudo nginx -t && sudo systemctl reload nginx
|
||||||
|
# sudo certbot --nginx -d arbpulse.wayool.com # issues cert + adds the 443 block + HTTP->HTTPS redirect
|
||||||
|
#
|
||||||
|
# certbot copies the location block into the TLS server it generates, so the
|
||||||
|
# SSE-friendly proxy settings below carry over to HTTPS.
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name arbpulse.wayool.com;
|
||||||
|
|
||||||
|
# Proxy everything to the app container (loopback-published by docker compose).
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:8080;
|
||||||
|
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;
|
||||||
|
|
||||||
|
# SSE (/api/stream): stream in real time, never buffer, keep long-lived.
|
||||||
|
proxy_buffering off;
|
||||||
|
proxy_cache off;
|
||||||
|
proxy_set_header Connection "";
|
||||||
|
proxy_read_timeout 3600s;
|
||||||
|
proxy_send_timeout 3600s;
|
||||||
|
chunked_transfer_encoding off;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user