Arslan1997 commited on
Commit
23b9370
·
1 Parent(s): c2dd07c

launching

Browse files
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, Caddy (automatic HTTPS) and, optionally, the video renderer.
 
 
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
- # Caddy terminates HTTPS for API_DOMAIN and proxies to the API; the worker and renderer are internal.
 
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