Spaces:
Runtime error
Runtime error
Commit ·
23b9370
1
Parent(s): c2dd07c
launching
Browse files- deploy/README.md +14 -1
- deploy/docker-compose.prod.yml +6 -2
- deploy/env.prod.example +2 -0
- deploy/nginx-notestack.conf +31 -0
- deploy/update.sh +13 -1
deploy/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
| 1 |
# Deploying the backend to a DigitalOcean Droplet
|
| 2 |
|
| 3 |
-
One Droplet runs the API, the job worker
|
|
|
|
|
|
|
| 4 |
The database is Neon. The frontend is on Cloudflare Pages.
|
| 5 |
|
| 6 |
## First time
|
|
@@ -22,6 +24,17 @@ The database is Neon. The frontend is on Cloudflare Pages.
|
|
| 22 |
6. **Google OAuth client**: redirect URI `https://api.notestack.ai/api/auth/google/callback`, JavaScript origin
|
| 23 |
`https://notestackai.pages.dev`.
|
| 24 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
## Every update
|
| 26 |
|
| 27 |
```bash
|
|
|
|
| 1 |
# Deploying the backend to a DigitalOcean Droplet
|
| 2 |
|
| 3 |
+
One Droplet runs the API, the job worker and, optionally, the video renderer. HTTPS comes from the reverse
|
| 4 |
+
proxy already on the Droplet (Nginx, see nginx-notestack.conf), or from the bundled Caddy (`CADDY=1`) on a
|
| 5 |
+
Droplet with nothing else on ports 80 and 443.
|
| 6 |
The database is Neon. The frontend is on Cloudflare Pages.
|
| 7 |
|
| 8 |
## First time
|
|
|
|
| 24 |
6. **Google OAuth client**: redirect URI `https://api.notestack.ai/api/auth/google/callback`, JavaScript origin
|
| 25 |
`https://notestackai.pages.dev`.
|
| 26 |
|
| 27 |
+
## Sharing the Droplet with other backends (Nginx)
|
| 28 |
+
|
| 29 |
+
The API listens on `127.0.0.1:8010` only (`API_PORT`). Point Nginx at it:
|
| 30 |
+
|
| 31 |
+
```bash
|
| 32 |
+
sudo cp /opt/notestack/deploy/nginx-notestack.conf /etc/nginx/sites-available/notestack
|
| 33 |
+
sudo ln -s /etc/nginx/sites-available/notestack /etc/nginx/sites-enabled/notestack
|
| 34 |
+
sudo nginx -t && sudo systemctl reload nginx
|
| 35 |
+
sudo certbot --nginx -d api.notestack.ai
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
## Every update
|
| 39 |
|
| 40 |
```bash
|
deploy/docker-compose.prod.yml
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
# Production stack for a single DigitalOcean Droplet. The database is Neon (DATABASE_URL in .env.prod).
|
| 2 |
# cd /opt/notestack/deploy && docker compose --env-file .env.prod -f docker-compose.prod.yml up -d --build
|
| 3 |
-
#
|
|
|
|
| 4 |
|
| 5 |
services:
|
| 6 |
api:
|
|
@@ -12,6 +13,8 @@ services:
|
|
| 12 |
command: >
|
| 13 |
sh -c "alembic upgrade head &&
|
| 14 |
uvicorn app.main:app --host 0.0.0.0 --port 8000 --proxy-headers --forwarded-allow-ips='*'"
|
|
|
|
|
|
|
| 15 |
volumes:
|
| 16 |
- appdata:/data
|
| 17 |
healthcheck:
|
|
@@ -39,9 +42,10 @@ services:
|
|
| 39 |
INTERNAL_TOKEN: ${INTERNAL_TOKEN} # must match the API's
|
| 40 |
profiles: ["render"] # optional: start with --profile render (needs about 2 GB of free RAM)
|
| 41 |
|
| 42 |
-
caddy:
|
| 43 |
image: caddy:2
|
| 44 |
restart: unless-stopped
|
|
|
|
| 45 |
ports:
|
| 46 |
- "80:80"
|
| 47 |
- "443:443"
|
|
|
|
| 1 |
# Production stack for a single DigitalOcean Droplet. The database is Neon (DATABASE_URL in .env.prod).
|
| 2 |
# cd /opt/notestack/deploy && docker compose --env-file .env.prod -f docker-compose.prod.yml up -d --build
|
| 3 |
+
# The API listens on 127.0.0.1:API_PORT (default 8010) for the reverse proxy already on this host (Nginx,
|
| 4 |
+
# Caddy...). On a Droplet with nothing else on ports 80/443, start the bundled Caddy with --profile caddy.
|
| 5 |
|
| 6 |
services:
|
| 7 |
api:
|
|
|
|
| 13 |
command: >
|
| 14 |
sh -c "alembic upgrade head &&
|
| 15 |
uvicorn app.main:app --host 0.0.0.0 --port 8000 --proxy-headers --forwarded-allow-ips='*'"
|
| 16 |
+
ports:
|
| 17 |
+
- "127.0.0.1:${API_PORT:-8010}:8000" # local only: the host proxy forwards API_DOMAIN here
|
| 18 |
volumes:
|
| 19 |
- appdata:/data
|
| 20 |
healthcheck:
|
|
|
|
| 42 |
INTERNAL_TOKEN: ${INTERNAL_TOKEN} # must match the API's
|
| 43 |
profiles: ["render"] # optional: start with --profile render (needs about 2 GB of free RAM)
|
| 44 |
|
| 45 |
+
caddy: # only on a Droplet with no other web server: --profile caddy
|
| 46 |
image: caddy:2
|
| 47 |
restart: unless-stopped
|
| 48 |
+
profiles: ["caddy"]
|
| 49 |
ports:
|
| 50 |
- "80:80"
|
| 51 |
- "443:443"
|
deploy/env.prod.example
CHANGED
|
@@ -3,6 +3,8 @@
|
|
| 3 |
|
| 4 |
# ---- Domains
|
| 5 |
API_DOMAIN=api.notestack.ai
|
|
|
|
|
|
|
| 6 |
ACME_EMAIL=arslan@firebird-technologies.com
|
| 7 |
ENV=production
|
| 8 |
API_URL=https://api.notestack.ai
|
|
|
|
| 3 |
|
| 4 |
# ---- Domains
|
| 5 |
API_DOMAIN=api.notestack.ai
|
| 6 |
+
# Local port the host reverse proxy (Nginx) forwards API_DOMAIN to. Change it if 8010 is taken.
|
| 7 |
+
API_PORT=8010
|
| 8 |
ACME_EMAIL=arslan@firebird-technologies.com
|
| 9 |
ENV=production
|
| 10 |
API_URL=https://api.notestack.ai
|
deploy/nginx-notestack.conf
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Nginx site for the Notestack API on a Droplet that already runs other backends.
|
| 2 |
+
# sudo cp /opt/notestack/deploy/nginx-notestack.conf /etc/nginx/sites-available/notestack
|
| 3 |
+
# sudo ln -s /etc/nginx/sites-available/notestack /etc/nginx/sites-enabled/notestack
|
| 4 |
+
# sudo nginx -t && sudo systemctl reload nginx
|
| 5 |
+
# sudo certbot --nginx -d api.notestack.ai # adds HTTPS and the 443 server block
|
| 6 |
+
# The API container listens on 127.0.0.1:8010 (API_PORT in deploy/.env.prod).
|
| 7 |
+
|
| 8 |
+
server {
|
| 9 |
+
listen 80;
|
| 10 |
+
listen [::]:80;
|
| 11 |
+
server_name api.notestack.ai;
|
| 12 |
+
|
| 13 |
+
# Voice samples, PDFs and other uploads.
|
| 14 |
+
client_max_body_size 220m;
|
| 15 |
+
|
| 16 |
+
location / {
|
| 17 |
+
proxy_pass http://127.0.0.1:8010;
|
| 18 |
+
proxy_http_version 1.1;
|
| 19 |
+
proxy_set_header Host $host;
|
| 20 |
+
proxy_set_header X-Real-IP $remote_addr;
|
| 21 |
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
| 22 |
+
proxy_set_header X-Forwarded-Proto $scheme;
|
| 23 |
+
proxy_set_header Connection "";
|
| 24 |
+
|
| 25 |
+
# Job progress and chat are server sent events: stream them, do not buffer or time out early.
|
| 26 |
+
proxy_buffering off;
|
| 27 |
+
proxy_cache off;
|
| 28 |
+
proxy_read_timeout 3600s;
|
| 29 |
+
proxy_send_timeout 3600s;
|
| 30 |
+
}
|
| 31 |
+
}
|
deploy/update.sh
CHANGED
|
@@ -2,6 +2,7 @@
|
|
| 2 |
# Deploy the latest code: pull, rebuild, restart, then check health.
|
| 3 |
# bash /opt/notestack/deploy/update.sh # API, worker, Caddy
|
| 4 |
# RENDER=1 bash /opt/notestack/deploy/update.sh # also the video renderer
|
|
|
|
| 5 |
set -euo pipefail
|
| 6 |
|
| 7 |
cd "$(dirname "$0")"
|
|
@@ -14,11 +15,22 @@ if grep -qE '=<|<(user|password|ep-xxxx|region|db)>' .env.prod; then
|
|
| 14 |
fi
|
| 15 |
|
| 16 |
profile=()
|
| 17 |
-
[ "${RENDER:-0}" = "1" ] && profile=(--profile render)
|
|
|
|
| 18 |
|
| 19 |
docker compose --env-file .env.prod -f docker-compose.prod.yml "${profile[@]}" up -d --build --remove-orphans
|
| 20 |
docker image prune -f >/dev/null
|
| 21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
domain=$(grep -E '^API_DOMAIN=' .env.prod | cut -d= -f2)
|
| 23 |
echo "==> Waiting for https://$domain/api/health"
|
| 24 |
for _ in $(seq 1 30); do
|
|
|
|
| 2 |
# Deploy the latest code: pull, rebuild, restart, then check health.
|
| 3 |
# bash /opt/notestack/deploy/update.sh # API, worker, Caddy
|
| 4 |
# RENDER=1 bash /opt/notestack/deploy/update.sh # also the video renderer
|
| 5 |
+
# CADDY=1 bash /opt/notestack/deploy/update.sh # bundled Caddy (only if nothing else uses ports 80/443)
|
| 6 |
set -euo pipefail
|
| 7 |
|
| 8 |
cd "$(dirname "$0")"
|
|
|
|
| 15 |
fi
|
| 16 |
|
| 17 |
profile=()
|
| 18 |
+
[ "${RENDER:-0}" = "1" ] && profile+=(--profile render)
|
| 19 |
+
[ "${CADDY:-0}" = "1" ] && profile+=(--profile caddy)
|
| 20 |
|
| 21 |
docker compose --env-file .env.prod -f docker-compose.prod.yml "${profile[@]}" up -d --build --remove-orphans
|
| 22 |
docker image prune -f >/dev/null
|
| 23 |
|
| 24 |
+
port=$(grep -E '^API_PORT=' .env.prod | cut -d= -f2)
|
| 25 |
+
port=${port:-8010}
|
| 26 |
+
echo "==> Waiting for the API on 127.0.0.1:$port"
|
| 27 |
+
for _ in $(seq 1 30); do
|
| 28 |
+
curl -fsS "http://127.0.0.1:$port/api/health" >/dev/null 2>&1 && break
|
| 29 |
+
sleep 4
|
| 30 |
+
done
|
| 31 |
+
curl -fsS "http://127.0.0.1:$port/api/health" || { echo "API not up. Logs: cd deploy && docker compose --env-file .env.prod -f docker-compose.prod.yml logs -f api"; exit 1; }
|
| 32 |
+
echo
|
| 33 |
+
|
| 34 |
domain=$(grep -E '^API_DOMAIN=' .env.prod | cut -d= -f2)
|
| 35 |
echo "==> Waiting for https://$domain/api/health"
|
| 36 |
for _ in $(seq 1 30); do
|