Afunana
Afunana Documentation

Deployment & Updates

Update workflow, version management, rollback, backup, and monitoring.

← All docs

This document covers how Afunana is built, deployed, updated, and backed up.


Update Workflow

Afunana runs on either Docker or Podman, auto-detected at install. Use whichever compose command is active on your host: docker compose, podman-compose, or docker-compose. The examples below use docker compose as shorthand.

Updating a running Afunana instance takes two commands — pull the newer image(s) and bring the stack back up. In Caddy proxy mode, the caddy profile is included so the proxy is updated too.

Alternatively, re-run the setup script and select the update option:

When setup.sh detects an existing installation it offers a short menu:

Option Action
Update Pull the newer image(s) and restart. Configuration, secrets, and data are preserved.
Reinstall Re-run the full install against the existing directory.
Reconfigure domain Change the public domain / TLS settings (Caddy mode) without a code change.

Choose Update for a routine version bump. The script pulls the latest images and restarts all containers. Configuration, secrets, and collection data are preserved across updates.

Updating means pulling a new application image (from Docker Hub, an internal registry, or an offline tarball) and restarting the containers. The marketing site is bundled inside the application image, but a customer install does not serve it; the public afunana.io host serves only two things to a customer host — the one-line setup.sh and the hourly, non-blocking version-check.

Database schema migrations run automatically on startup. No manual SQL steps are needed.

Offline / Internal-Registry Updates

If the host has no Docker Hub access, update from the same sources used at install — either an internal registry mirror or an offline delivery tarball. Re-running setup.sh in the install directory will auto-load a tarball it finds there.


Reverse Proxy (Customer-Managed)

This section is the canonical reference for customer-managed reverse-proxy requirements. Other docs link here rather than restating the rules.

Enterprises that prefer their own reverse proxy (nginx, F5, HAProxy, Azure App Gateway) can run Afunana without the bundled Caddy. The customer's proxy must then replicate what Caddy did automatically. At a minimum the proxy must do four things, each of which, if missing, breaks the app in a specific way:

  1. Terminate TLS — present the customer's certificate and forward decrypted traffic to the app's HTTP port.
  2. Strip the /api prefix (most critical) — the frontend calls /api/... but the app's routes do not include /api; if the prefix is not stripped the app returns 405 or HTML instead of JSON.
  3. Don't buffer SSE responses — chat answers stream token-by-token, so a buffering proxy makes chat look frozen; disable response buffering and allow a long read timeout.
  4. Forward the host and client headers — pass Host, X-Forwarded-For, and X-Forwarded-Proto so the app builds correct URLs and CORS. Also allow large request bodies so attachment uploads are not rejected.

The app binds to 127.0.0.1:18080 when the proxy runs on the same host, or to all interfaces (firewall-restricted) when the proxy is on a separate host. Set the public URL the proxy serves as FRONTEND_URL.

The app now sends a SPA-friendly Content-Security-Policy (strict on /api, relaxed on HTML/assets), so the proxy no longer needs to hide or replace the CSP header -- the only special handling required is the /api strip.


Network & Firewall Requirements

When running with a customer-managed proxy and/or an external database, allow the following egress and ingress paths:

From To Port Purpose
App host SQL Server 1433 Database connection
App host LLM provider endpoint (e.g. Azure OpenAI) 443 Model API calls
App host Docker Hub / registry 443 One-time image pull (skip if air-gapped/mirrored)
Users Proxy 443 User access (HTTPS)
Proxy App 18080 (e.g.) Proxy-to-app forwarding

Version Management

Version File

Versions use a zero-padded 00.XX.XX scheme (e.g. 00.18.35) — never major.minor.patch JSON. The current application version and the latest-available version are tracked as 00.XX.XX strings (surfaced by the app's health check and its published version file).

Each deploy increments the patch segment automatically (00.18.3400.18.35).

Update Checks

The application compares the running version against latest-version.json hosted on the Afunana static site. The Admin UI displays a notification when a newer version is available.

The update check fetches the latest version, compares, caches the result for one hour, and reports whether an update is available.


Developer Deploy Flow

The developer deployment pipeline runs from a Windows workstation through GitHub Actions to Docker Hub.

Step-by-Step

  1. Developer runs deploy.ps1 on Windows.
  2. The script deletes any existing .vsix files from the vscode/ directory.
  3. The script bumps the patch version in version.json.
  4. Changes are committed and pushed to the master branch on GitHub.
  5. GitHub Actions triggers the CI/CD pipeline.

The deploy script never touches customer servers. It only builds, pushes, and commits.


CI/CD Pipeline

The GitHub Actions workflow triggers on every push to master:

  1. Frontend build -- Runs npm ci and npm run build in the client directory.
  2. Docker build -- Built on Red Hat UBI 9 (ubi9/python-312), split into a shared base image plus a thin application image.
  3. Docker push -- Pushes to Docker Hub with two tags:
Tag Description
latest Most recent build from master
00.XX.XX Pinned version (e.g., 00.18.35)

The Docker image is private. Pulling it requires a valid Docker Hub token.


Rollback

To roll back to a specific version, pin the image tag in docker-compose.yml to the desired 00.XX.XX tag and restart; to return to the latest build, set the tag back to latest and pull.

Database schema changes are forward-only and idempotent. Rolling back the application code does not undo schema changes, but new columns and tables are added safely without breaking older code.


Backup & Restore

Automated Daily Backups (bundled SQL Server)

In bundled-DB mode the installer configures an automated daily database backup via cron at 02:00 UTC (script /opt/afunana/scripts/backup-db.sh), retaining 7 days of .bak files in /opt/afunana/backups/. No manual action is required for routine database backups — the steps below are for ad-hoc snapshots or migrating to a new host.

TDE certificate vault — critical. With TDE encryption at rest enabled, a database backup is useless without its certificate. The installer backs up the TDE certificate and private key to /opt/afunana/tde-cert-backup/ (protected by the tde_cert_password secret). Store this directory off-box in a secure vault. If you lose it, an encrypted database restore on a new server cannot be opened.

External SQL Server. When DB_MODE=external, database backups, encryption, and retention are the customer's DBA responsibility — Afunana does not back up a SQL Server it does not own. The items below still apply to the on-disk collection data, logs, and secrets.

What to Back Up

Component Location Type
Database backups /opt/afunana/backups/ Daily .bak files (bundled mode)
SQL Server data Docker/Podman volume sqlserver_data Container volume (bundled mode)
TDE certificate /opt/afunana/tde-cert-backup/ Files on disk (store off-box)
Collection data /opt/afunana/backend/Data/ Files on disk
Application logs /opt/afunana/Log/ Files on disk
Secrets /opt/afunana/secrets/ Files on disk
Compose + env /opt/afunana/docker-compose.yml, .env, backend/.env, backend/seed.env Files on disk

Restoring

  1. Stop all containers.
  2. Restore the database volume from the backup (or restore a database backup file). On a new host, first restore the encryption (TDE) certificate before opening the encrypted database.
  3. Copy the collection data back into place.
  4. Copy the secrets back into place (and the encryption-certificate backup if relocating).
  5. Start the containers again.

Deploy Receiver (Legacy)

deploy_receiver.py is dead legacy code — it is not installed by setup.sh and is unused. Deploys to the project's own servers run via SSH-pull from GitHub Actions; customers update by pulling the image as described in Update Workflow.


Monitoring

Health Endpoint

Verifies the application process is running and the database connection is active. (Port 8001 is container-internal only; from the host use 18080.)

Container Logs

Each service streams its own log; the reverse-proxy and database logs are present only in the modes that run those services.

Container Status

The services for your modes should show status Up: always afunana-app; plus caddy (Caddy mode) and sqlserver (bundled-DB mode). init-frontend runs once and exits — that is expected.

Disk Cleanup

After updates, clean up old images and monitor disk usage.