mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-07 07:55:16 +02:00
feat: add update script
This commit is contained in:
parent
062a97d25e
commit
ca44a4df1e
3 changed files with 459 additions and 57 deletions
|
|
@ -7,6 +7,10 @@ By default, the Dograh API container runs a single uvicorn worker. For productio
|
|||
|
||||
This page covers how the multi-worker setup works, how to choose a worker count at install time, and how to change it on a running stack.
|
||||
|
||||
<Warning>
|
||||
Multi-worker support requires **Dograh v1.29.0 or newer**. Earlier releases used `uvicorn --workers` and ship a different `setup_remote.sh` / `start_services_docker.sh` / `nginx.conf` layout — the steps below will not work on them. If your stack is older, [update first](/deployment/update) and then come back to this page.
|
||||
</Warning>
|
||||
|
||||
## How it works
|
||||
|
||||
The API container starts `FASTAPI_WORKERS` separate uvicorn processes, each bound to its own port (`8000`, `8001`, `8002`, …). nginx exposes a single upstream `dograh_api` that includes all worker ports and routes new requests to whichever worker currently has the **fewest active connections**.
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@ description: "Update your self-hosted Dograh stack to a newer image version"
|
|||
|
||||
This guide covers updating a Dograh stack you've already deployed with [Docker](/deployment/docker) or a [custom domain](/deployment/custom-domain). You run commands from the same directory that contains your `docker-compose.yaml` (this is the `dograh/` directory if you used `setup_remote.sh`).
|
||||
|
||||
<Note>
|
||||
This guide assumes you deployed in **prebuilt mode** — i.e. your stack pulls official `dograh-api` / `dograh-ui` images from a registry. If you deployed in **build mode** (a `docker-compose.override.yaml` exists in your `dograh/` directory), the update flow is different — see [Updating a source build](#updating-a-source-build) at the bottom.
|
||||
</Note>
|
||||
There are three update flows depending on how you deployed:
|
||||
|
||||
- **Remote, prebuilt mode** (most users) — use [`update_remote.sh`](#remote-prebuilt-mode-recommended) below.
|
||||
- **Local Docker** — pull images and restart; see [Local deployment](#local-deployment).
|
||||
- **Remote, build mode** (you have a `docker-compose.override.yaml`) — update via git; see [Updating a source build](#updating-a-source-build).
|
||||
|
||||
## Find an image version
|
||||
|
||||
|
|
@ -20,77 +22,59 @@ Each release is published under two kinds of tags:
|
|||
|
||||
| Tag style | Example | When to use |
|
||||
|-----------|---------|-------------|
|
||||
| **Release tag** | `v0.8.2` | Stable, recommended for production |
|
||||
| **Release tag** | `v1.29.0` | Stable, recommended for production |
|
||||
| **Git commit SHA** | `a1b2c3d` | Bleeding edge — any commit merged to `main` |
|
||||
| `latest` | `latest` | Tracks the most recent release tag |
|
||||
|
||||
<Warning>
|
||||
Always update **`dograh-api`** and **`dograh-ui`** to the **same tag**. The two images are built from the same commit and the UI expects API responses in a matching shape — mixing versions will break the app.
|
||||
Always update **`dograh-api`** and **`dograh-ui`** to the **same tag**. The two images are built from the same commit and the UI expects API responses in a matching shape — mixing versions will break the app. `update_remote.sh` handles this for you automatically.
|
||||
</Warning>
|
||||
|
||||
## Option A: Update to the latest release
|
||||
## Remote, prebuilt mode (recommended)
|
||||
|
||||
If your `docker-compose.yaml` uses `:latest` (the default), just pull and restart:
|
||||
`update_remote.sh` is the supported path for updating a stack created with `setup_remote.sh`. In one shot it:
|
||||
|
||||
<CodeGroup>
|
||||
```bash Local deployment
|
||||
docker compose down
|
||||
docker compose up --pull always
|
||||
```
|
||||
```bash Remote deployment
|
||||
cd dograh
|
||||
sudo docker compose --profile remote down
|
||||
sudo docker compose --profile remote up --pull always
|
||||
```
|
||||
</CodeGroup>
|
||||
- Asks for a target version (defaults to the latest release tag on GitHub).
|
||||
- Pulls `docker-compose.yaml` at that version and pins both `api` and `ui` images to it.
|
||||
- Regenerates `nginx.conf` and `turnserver.conf` from the upstream templates, so newer features (like [multi-worker scaling](/deployment/scaling)) are wired up correctly without manual editing.
|
||||
- Reads your existing `.env` and appends any new required keys with safe defaults — your `OSS_JWT_SECRET`, `TURN_SECRET`, and other values are never touched.
|
||||
- Backs up every file it changes with a `.bak.<timestamp>` suffix.
|
||||
|
||||
`--pull always` forces Docker to fetch the latest `:latest` from the registry instead of reusing your cached image.
|
||||
|
||||
## Option B: Pin a specific tag
|
||||
|
||||
To update (or roll back) to a specific release or commit, edit `docker-compose.yaml` and change the `image:` lines for both `api` and `ui` services to the same tag.
|
||||
|
||||
Open the file:
|
||||
From your install directory:
|
||||
|
||||
```bash
|
||||
nano docker-compose.yaml
|
||||
cd dograh
|
||||
curl -o update_remote.sh https://raw.githubusercontent.com/dograh-hq/dograh/main/scripts/update_remote.sh
|
||||
bash update_remote.sh
|
||||
```
|
||||
|
||||
Find these two lines:
|
||||
You'll be prompted for the target version. Non-interactive callers can set it via environment variable and skip the confirmation prompt:
|
||||
|
||||
```yaml
|
||||
api:
|
||||
image: ${REGISTRY:-dograhai}/dograh-api:latest
|
||||
ui:
|
||||
image: ${REGISTRY:-dograhai}/dograh-ui:latest
|
||||
```bash
|
||||
TARGET_VERSION=v1.29.0 DOGRAH_UPDATE_YES=1 bash update_remote.sh
|
||||
```
|
||||
|
||||
Replace `:latest` with your chosen tag on **both** services — for example:
|
||||
After the script finishes, apply the update by recreating the stack:
|
||||
|
||||
```yaml
|
||||
api:
|
||||
image: ${REGISTRY:-dograhai}/dograh-api:v0.8.2
|
||||
ui:
|
||||
image: ${REGISTRY:-dograhai}/dograh-ui:v0.8.2
|
||||
```bash
|
||||
sudo docker compose --profile remote down
|
||||
sudo docker compose --profile remote up -d --pull always
|
||||
```
|
||||
|
||||
<Note>
|
||||
You can use either registry. Leave `REGISTRY` unset for Docker Hub (`dograhai`), or export `REGISTRY=ghcr.io/dograh-hq` to pull from GitHub Container Registry.
|
||||
The script overwrites `docker-compose.yaml`, `nginx.conf`, and `turnserver.conf` from upstream templates. If you've made local edits to any of these (extra environment variables, custom ports, modified nginx routes), check the `.bak.<timestamp>` files after the update and re-apply your edits.
|
||||
</Note>
|
||||
|
||||
Then bring the stack down and back up:
|
||||
## Local deployment
|
||||
|
||||
<CodeGroup>
|
||||
```bash Local deployment
|
||||
For local Docker installs (the [Quick Start](/deployment/docker#quick-start) flow or `setup_local.sh`), there are no host-side config files to refresh — pull new images and restart:
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
docker compose up --pull always
|
||||
```
|
||||
```bash Remote deployment
|
||||
cd dograh
|
||||
sudo docker compose --profile remote down
|
||||
sudo docker compose --profile remote up --pull always
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
To pin a specific version instead of `latest`, edit `docker-compose.yaml` and change both `image:` lines for `api` and `ui` to the same tag (e.g. `:v1.29.0`), then run the commands above.
|
||||
|
||||
## Verify the update
|
||||
|
||||
|
|
@ -105,12 +89,24 @@ You should see the API and UI both running the tag you pinned.
|
|||
Hit the health endpoint to confirm the API is responding:
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/api/v1/health
|
||||
curl -k https://YOUR_SERVER_IP/api/v1/health # remote
|
||||
curl http://localhost:8000/api/v1/health # local
|
||||
```
|
||||
|
||||
## Roll back
|
||||
|
||||
If something breaks, roll back by pinning the previous tag using the same process in **Option B** and restarting. Your Postgres data volume persists across `down`/`up` cycles, so agents and call history are preserved.
|
||||
`update_remote.sh` saves backups of every file it touched. To roll back, restore them and recreate the stack — the exact commands (including the timestamp it used) are printed at the end of the script's output. The generic form:
|
||||
|
||||
```bash
|
||||
cd dograh
|
||||
for f in docker-compose.yaml nginx.conf turnserver.conf .env; do
|
||||
[[ -f "$f.bak.<timestamp>" ]] && cp "$f.bak.<timestamp>" "$f"
|
||||
done
|
||||
sudo docker compose --profile remote down
|
||||
sudo docker compose --profile remote up -d
|
||||
```
|
||||
|
||||
Your Postgres data volume persists across `down`/`up` cycles, so agents and call history are preserved.
|
||||
|
||||
<Warning>
|
||||
Rolling back across a database migration is not always safe — if the newer release ran a schema migration, downgrading may leave the DB in a state the older API doesn't understand. If in doubt, [open an issue](https://github.com/dograh-hq/dograh/issues) before rolling back.
|
||||
|
|
@ -118,21 +114,29 @@ Rolling back across a database migration is not always safe — if the newer rel
|
|||
|
||||
## Updating a source build
|
||||
|
||||
If you deployed in **build mode** (you'll have a `docker-compose.override.yaml` in your `dograh/` directory), there are no image tags to pull — you update by pulling new source and rebuilding:
|
||||
If you deployed in **build mode** (you'll have a `docker-compose.override.yaml` in your install directory), `update_remote.sh` deliberately refuses to run — you already have the full repo locally and update via git:
|
||||
|
||||
```bash
|
||||
cd dograh
|
||||
git fetch
|
||||
|
||||
# Track latest main:
|
||||
git pull
|
||||
# Or pin to a specific release:
|
||||
git checkout v1.29.0
|
||||
|
||||
# Pick up pipecat and other submodule bumps
|
||||
git submodule update --init --recursive
|
||||
|
||||
# Rebuild and restart
|
||||
sudo docker compose --profile remote build
|
||||
sudo docker compose --profile remote up -d
|
||||
```
|
||||
|
||||
To roll back, check out an earlier commit or tag and rebuild:
|
||||
<Warning>
|
||||
If you update the `pipecat` submodule, you **must** run `git submodule update --init --recursive` before rebuilding, or the Docker build will not pick up `pipecat` changes.
|
||||
</Warning>
|
||||
|
||||
```bash
|
||||
git checkout <previous-tag-or-sha>
|
||||
sudo docker compose --profile remote build
|
||||
sudo docker compose --profile remote up -d
|
||||
```
|
||||
If you maintain a fork with local customizations on top of upstream, merging conflicts in `docker-compose.yaml`, `nginx.conf`, `turnserver.conf`, or `setup_remote.sh` is up to you — resolve them as you would any other git merge. Leave `OSS_JWT_SECRET` and `TURN_SECRET` in `.env` unchanged across updates to preserve sessions and WebRTC auth.
|
||||
|
||||
The same migration warning above applies: rolling back across a schema change can leave the DB in a state the older API can't read.
|
||||
|
|
|
|||
394
scripts/update_remote.sh
Executable file
394
scripts/update_remote.sh
Executable file
|
|
@ -0,0 +1,394 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
REPO="dograh-hq/dograh"
|
||||
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
||||
|
||||
echo -e "${BLUE}"
|
||||
echo "╔══════════════════════════════════════════════════════════════╗"
|
||||
echo "║ Dograh Remote Update ║"
|
||||
echo "║ Refresh host-side configs and pin api/ui image versions ║"
|
||||
echo "╚══════════════════════════════════════════════════════════════╝"
|
||||
echo -e "${NC}"
|
||||
|
||||
# Refuse outside an install — nothing to update if these aren't here.
|
||||
if [[ ! -f docker-compose.yaml ]]; then
|
||||
echo -e "${RED}Error: docker-compose.yaml not found in $(pwd)${NC}"
|
||||
echo -e "${RED}Run this script from your Dograh install directory${NC}"
|
||||
echo -e "${RED}(the 'dograh/' folder created by setup_remote.sh).${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f .env ]]; then
|
||||
echo -e "${RED}Error: .env not found in $(pwd)${NC}"
|
||||
echo -e "${RED}This script updates an existing install — there is nothing here to update.${NC}"
|
||||
echo -e "${RED}For a fresh install, see https://docs.dograh.com/deployment/docker${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build-mode installs update via git, not via this script. The presence of an
|
||||
# override file is the definitive marker (created by setup_remote.sh in build
|
||||
# mode and not in prebuilt mode).
|
||||
if [[ -f docker-compose.override.yaml ]]; then
|
||||
echo -e "${YELLOW}Build-mode install detected (docker-compose.override.yaml present).${NC}"
|
||||
echo ""
|
||||
echo -e "${YELLOW}This script is for prebuilt installs only. For build mode, update via git:${NC}"
|
||||
echo ""
|
||||
echo -e " ${BLUE}git fetch${NC}"
|
||||
echo -e " ${BLUE}git checkout <tag> # or: git pull${NC}"
|
||||
echo -e " ${BLUE}git submodule update --init --recursive${NC}"
|
||||
echo -e " ${BLUE}sudo docker compose --profile remote build${NC}"
|
||||
echo -e " ${BLUE}sudo docker compose --profile remote up -d${NC}"
|
||||
echo ""
|
||||
echo -e "${YELLOW}See https://docs.dograh.com/deployment/update#updating-a-source-build${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
### Discover existing config from .env
|
||||
###############################################################################
|
||||
|
||||
# Save anything the caller exported before we overwrite from .env.
|
||||
_caller_FASTAPI_WORKERS="$FASTAPI_WORKERS"
|
||||
_caller_TARGET_VERSION="$TARGET_VERSION"
|
||||
|
||||
set -a
|
||||
# shellcheck disable=SC1091
|
||||
. ./.env
|
||||
set +a
|
||||
|
||||
# SERVER_IP isn't a literal key in .env — derive it from BACKEND_API_ENDPOINT.
|
||||
if [[ -z "$SERVER_IP" ]]; then
|
||||
if [[ -n "$BACKEND_API_ENDPOINT" ]]; then
|
||||
SERVER_IP="${BACKEND_API_ENDPOINT#https://}"
|
||||
SERVER_IP="${SERVER_IP#http://}"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "$SERVER_IP" ]]; then
|
||||
echo -e "${RED}Error: could not determine SERVER_IP from .env${NC}"
|
||||
echo -e "${RED}Expected BACKEND_API_ENDPOINT=https://<ip> in .env${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$TURN_SECRET" ]]; then
|
||||
echo -e "${RED}Error: TURN_SECRET not found in .env${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Reapply caller overrides on top of sourced .env so e.g. FASTAPI_WORKERS=8 ./update_remote.sh works.
|
||||
[[ -n "$_caller_FASTAPI_WORKERS" ]] && FASTAPI_WORKERS="$_caller_FASTAPI_WORKERS"
|
||||
[[ -n "$_caller_TARGET_VERSION" ]] && TARGET_VERSION="$_caller_TARGET_VERSION"
|
||||
|
||||
###############################################################################
|
||||
### Determine target version
|
||||
###############################################################################
|
||||
|
||||
if [[ -z "$TARGET_VERSION" ]]; then
|
||||
echo -e "${BLUE}Fetching latest release tag from GitHub...${NC}"
|
||||
LATEST_TAG=$(curl -fsSL "https://api.github.com/repos/$REPO/releases/latest" 2>/dev/null \
|
||||
| grep -E '"tag_name":' | head -1 \
|
||||
| sed -E 's/.*"tag_name":[[:space:]]*"([^"]+)".*/\1/' || true)
|
||||
|
||||
if [[ -z "$LATEST_TAG" ]]; then
|
||||
echo -e "${YELLOW}Could not auto-discover latest tag — defaulting to 'main'.${NC}"
|
||||
LATEST_TAG="main"
|
||||
fi
|
||||
|
||||
if [[ -t 0 ]]; then
|
||||
echo ""
|
||||
echo -e "${YELLOW}Target version (release tag like v1.29.0, or 'main' for bleeding edge):${NC}"
|
||||
read -p "[$LATEST_TAG]: " TARGET_VERSION
|
||||
TARGET_VERSION="${TARGET_VERSION:-$LATEST_TAG}"
|
||||
else
|
||||
TARGET_VERSION="$LATEST_TAG"
|
||||
fi
|
||||
fi
|
||||
|
||||
# "latest" isn't a real ref on GitHub — treat it as "latest release".
|
||||
if [[ "$TARGET_VERSION" == "latest" ]]; then
|
||||
TARGET_VERSION=$(curl -fsSL "https://api.github.com/repos/$REPO/releases/latest" 2>/dev/null \
|
||||
| grep -E '"tag_name":' | head -1 \
|
||||
| sed -E 's/.*"tag_name":[[:space:]]*"([^"]+)".*/\1/' || true)
|
||||
if [[ -z "$TARGET_VERSION" ]]; then
|
||||
echo -e "${RED}Error: could not resolve 'latest' to a release tag${NC}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Validate the tag/branch actually exists by HEAD-ing the compose file at that ref.
|
||||
RAW_BASE="https://raw.githubusercontent.com/$REPO/$TARGET_VERSION"
|
||||
echo -e "${BLUE}Validating target version: $TARGET_VERSION...${NC}"
|
||||
if ! curl -fsI "$RAW_BASE/docker-compose.yaml" >/dev/null 2>&1; then
|
||||
echo -e "${RED}Error: docker-compose.yaml not found at $TARGET_VERSION${NC}"
|
||||
echo -e "${RED}Check the tag exists at: https://github.com/$REPO/releases${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ Target version is valid${NC}"
|
||||
|
||||
###############################################################################
|
||||
### Reconcile required keys that may be missing on older installs
|
||||
###############################################################################
|
||||
|
||||
if [[ -z "$FASTAPI_WORKERS" ]]; then
|
||||
if [[ -t 0 ]]; then
|
||||
echo ""
|
||||
echo -e "${YELLOW}FASTAPI_WORKERS not set in .env. Number of uvicorn workers nginx will load-balance:${NC}"
|
||||
read -p "[4]: " FASTAPI_WORKERS
|
||||
FASTAPI_WORKERS="${FASTAPI_WORKERS:-4}"
|
||||
else
|
||||
FASTAPI_WORKERS="4"
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! [[ "$FASTAPI_WORKERS" =~ ^[1-9][0-9]*$ ]]; then
|
||||
echo -e "${RED}Error: FASTAPI_WORKERS must be a positive integer (got: $FASTAPI_WORKERS)${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
### Summary + confirmation
|
||||
###############################################################################
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}Update plan:${NC}"
|
||||
echo -e " Server IP: ${BLUE}$SERVER_IP${NC}"
|
||||
echo -e " Target version: ${BLUE}$TARGET_VERSION${NC}"
|
||||
echo -e " FastAPI workers: ${BLUE}$FASTAPI_WORKERS${NC} (ports 8000..$((8000 + FASTAPI_WORKERS - 1)))"
|
||||
echo ""
|
||||
echo -e "${YELLOW}Files that will be replaced (backups saved with suffix .bak.$TIMESTAMP):${NC}"
|
||||
echo " - docker-compose.yaml (pulled from GitHub at $TARGET_VERSION)"
|
||||
echo " - nginx.conf (regenerated from this script's template)"
|
||||
echo " - turnserver.conf (regenerated from this script's template)"
|
||||
echo " - .env (existing values preserved; missing keys appended)"
|
||||
echo ""
|
||||
echo -e "${YELLOW}Any local customizations to these files will be overwritten — check the backup${NC}"
|
||||
echo -e "${YELLOW}files if you need to re-apply edits afterwards.${NC}"
|
||||
echo ""
|
||||
|
||||
if [[ -t 0 && "$DOGRAH_UPDATE_YES" != "1" ]]; then
|
||||
read -p "Proceed? [y/N]: " confirm
|
||||
if ! [[ "$confirm" =~ ^[Yy] ]]; then
|
||||
echo -e "${RED}Aborted.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
### Step 1 — backups
|
||||
###############################################################################
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}[1/5] Backing up existing files...${NC}"
|
||||
for f in docker-compose.yaml nginx.conf turnserver.conf .env; do
|
||||
if [[ -f "$f" ]]; then
|
||||
cp -p "$f" "$f.bak.$TIMESTAMP"
|
||||
echo -e " ${GREEN}✓ $f → $f.bak.$TIMESTAMP${NC}"
|
||||
fi
|
||||
done
|
||||
|
||||
###############################################################################
|
||||
### Step 2 — docker-compose.yaml (download + pin image tags)
|
||||
###############################################################################
|
||||
|
||||
echo -e "${BLUE}[2/5] Downloading docker-compose.yaml at $TARGET_VERSION...${NC}"
|
||||
curl -fsSL -o docker-compose.yaml "$RAW_BASE/docker-compose.yaml"
|
||||
|
||||
# Pin api/ui image tags for release tags (v*). Leave :latest alone if we're
|
||||
# tracking a branch like 'main' so up --pull always still grabs the newest build.
|
||||
if [[ "$TARGET_VERSION" =~ ^v ]]; then
|
||||
sed -i.tmp -E "s#(dograh-(api|ui)):latest#\1:$TARGET_VERSION#g" docker-compose.yaml
|
||||
rm -f docker-compose.yaml.tmp
|
||||
echo -e "${GREEN}✓ docker-compose.yaml updated; images pinned to $TARGET_VERSION${NC}"
|
||||
else
|
||||
echo -e "${GREEN}✓ docker-compose.yaml updated (image tags left at :latest)${NC}"
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
### Step 3 — nginx.conf (regenerate from embedded template)
|
||||
###############################################################################
|
||||
|
||||
echo -e "${BLUE}[3/5] Regenerating nginx.conf...${NC}"
|
||||
{
|
||||
echo "# Backend API workers — one uvicorn process per port, balanced by least_conn."
|
||||
echo "# Generated by update_remote.sh; regenerate to change worker count."
|
||||
echo "upstream dograh_api {"
|
||||
echo " least_conn;"
|
||||
for ((i=0; i<FASTAPI_WORKERS; i++)); do
|
||||
port=$((8000 + i))
|
||||
echo " server api:$port max_fails=3 fail_timeout=10s;"
|
||||
done
|
||||
echo " keepalive 32;"
|
||||
echo "}"
|
||||
echo ""
|
||||
cat << 'NGINX_EOF'
|
||||
server {
|
||||
listen 80;
|
||||
server_name SERVER_IP_PLACEHOLDER;
|
||||
|
||||
# Redirect all HTTP to HTTPS
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name SERVER_IP_PLACEHOLDER;
|
||||
|
||||
ssl_certificate /etc/nginx/certs/local.crt;
|
||||
ssl_certificate_key /etc/nginx/certs/local.key;
|
||||
|
||||
# Basic TLS settings
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
# Backend API and WebSockets - bypass the UI, go straight to the
|
||||
# api workers via the least_conn upstream defined above.
|
||||
location /api/v1/ {
|
||||
proxy_pass http://dograh_api;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
# Retry on a dead/restarting worker
|
||||
proxy_next_upstream error timeout http_502 http_503 http_504;
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
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 https;
|
||||
|
||||
# Long-lived WebSockets (audio streaming, signaling)
|
||||
proxy_read_timeout 3600s;
|
||||
proxy_send_timeout 3600s;
|
||||
|
||||
# Don't buffer streamed responses
|
||||
proxy_buffering off;
|
||||
client_max_body_size 100M;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://ui:3010;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
# Important for WebSockets / hot reload etc.
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
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 https;
|
||||
|
||||
# Rewrite localhost MinIO URLs in API responses to use current domain
|
||||
sub_filter 'http://localhost:9000/voice-audio/' 'https://$host/voice-audio/';
|
||||
sub_filter_once off;
|
||||
sub_filter_types application/json text/html;
|
||||
}
|
||||
|
||||
location /voice-audio/ {
|
||||
proxy_pass http://minio:9000/voice-audio/;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
|
||||
# Headers for file downloads from MinIO
|
||||
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 https;
|
||||
|
||||
# Allow large file downloads
|
||||
proxy_buffering off;
|
||||
client_max_body_size 100M;
|
||||
}
|
||||
}
|
||||
NGINX_EOF
|
||||
} > nginx.conf
|
||||
|
||||
sed -i.tmp "s/SERVER_IP_PLACEHOLDER/$SERVER_IP/g" nginx.conf && rm -f nginx.conf.tmp
|
||||
echo -e "${GREEN}✓ nginx.conf regenerated${NC}"
|
||||
|
||||
###############################################################################
|
||||
### Step 4 — turnserver.conf (regenerate from embedded template)
|
||||
###############################################################################
|
||||
|
||||
echo -e "${BLUE}[4/5] Regenerating turnserver.conf...${NC}"
|
||||
cat > turnserver.conf << TURN_EOF
|
||||
# Coturn TURN Server - Docker Configuration
|
||||
# Auto-generated by update_remote.sh
|
||||
|
||||
# Listener ports
|
||||
listening-port=3478
|
||||
tls-listening-port=5349
|
||||
|
||||
# Relay port range
|
||||
min-port=49152
|
||||
max-port=49200
|
||||
|
||||
# Network - external IP for NAT traversal
|
||||
external-ip=$SERVER_IP
|
||||
|
||||
# Realm
|
||||
realm=dograh.com
|
||||
|
||||
# Authentication (TURN REST API with time-limited credentials)
|
||||
use-auth-secret
|
||||
static-auth-secret=$TURN_SECRET
|
||||
|
||||
# Security
|
||||
fingerprint
|
||||
no-cli
|
||||
no-multicast-peers
|
||||
|
||||
# Logging
|
||||
log-file=stdout
|
||||
TURN_EOF
|
||||
echo -e "${GREEN}✓ turnserver.conf regenerated${NC}"
|
||||
|
||||
###############################################################################
|
||||
### Step 5 — reconcile .env (append missing keys; never overwrite existing)
|
||||
###############################################################################
|
||||
|
||||
echo -e "${BLUE}[5/5] Reconciling .env...${NC}"
|
||||
if ! grep -q "^FASTAPI_WORKERS=" .env; then
|
||||
{
|
||||
echo ""
|
||||
echo "# Number of uvicorn worker processes; nginx load-balances across them"
|
||||
echo "# (ports 8000..$((8000 + FASTAPI_WORKERS - 1))) with least_conn."
|
||||
echo "FASTAPI_WORKERS=$FASTAPI_WORKERS"
|
||||
} >> .env
|
||||
echo -e "${GREEN}✓ Added FASTAPI_WORKERS=$FASTAPI_WORKERS to .env${NC}"
|
||||
else
|
||||
echo -e "${GREEN}✓ .env already has FASTAPI_WORKERS — left unchanged${NC}"
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
### Done — print restart + rollback instructions
|
||||
###############################################################################
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}╔══════════════════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${GREEN}║ Update Prepared! ║${NC}"
|
||||
echo -e "${GREEN}╚══════════════════════════════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
echo -e "Backups: ${BLUE}*.bak.$TIMESTAMP${NC}"
|
||||
echo ""
|
||||
echo -e "${YELLOW}To apply, recreate the stack:${NC}"
|
||||
echo ""
|
||||
echo -e " ${BLUE}sudo docker compose --profile remote down${NC}"
|
||||
echo -e " ${BLUE}sudo docker compose --profile remote up -d --pull always${NC}"
|
||||
echo ""
|
||||
echo -e "${YELLOW}To roll back, restore the backups and recreate:${NC}"
|
||||
echo ""
|
||||
echo -e " ${BLUE}for f in docker-compose.yaml nginx.conf turnserver.conf .env; do${NC}"
|
||||
echo -e " ${BLUE} [[ -f \"\$f.bak.$TIMESTAMP\" ]] && cp \"\$f.bak.$TIMESTAMP\" \"\$f\"${NC}"
|
||||
echo -e " ${BLUE}done${NC}"
|
||||
echo -e " ${BLUE}sudo docker compose --profile remote down && sudo docker compose --profile remote up -d${NC}"
|
||||
echo ""
|
||||
Loading…
Add table
Add a link
Reference in a new issue