The AppBox middleware
| Hostname | Role | Routes |
|---|---|---|
api.getappbox.com |
AppBox client API | /api/v1/* |
install.getappbox.com |
Install / proxy layer | /cors, /install/**, /appinfo/** |
Contents: Quick start · Configuration · API reference · Operations · Support
Docker Compose uses the variables listed in its environment block. Set them in your shell or deployment environment. The Docker run and native examples below use a .env file:
cp .env.example .envFill in the values (see Configuration).
docker compose pull appdocker compose up -d appcurl http://localhost:2551/docker pull ghcr.io/getappbox/middleware:latestdocker run -d --name middleware --env-file .env -p 8080:8080 --restart unless-stopped ghcr.io/getappbox/middleware:latestPin a specific published version in production rather than tracking latest (replace VERSION):
docker run -d --name middleware --env-file .env -p 8080:8080 --restart unless-stopped ghcr.io/getappbox/middleware:VERSIONdocker build -t middleware:latest .docker run -d --name middleware --env-file .env -p 8080:8080 middleware:latestThe image is a two-stage build (Go 1.27.3 builder → scratch runtime, statically linked executable), runs as the non-root user 65532:65532, and ships a HEALTHCHECK that probes the HTTP server:
docker inspect --format '{{.State.Health.Status}}' middlewareInstall the unit file at /etc/systemd/system/middleware.service (middleware.service in this repo). It runs /opt/appbox-middleware/bin/middleware and loads secrets from /opt/appbox-middleware/.env.
sudo systemctl daemon-reload && sudo systemctl enable --now middlewareDocker Compose (pulls the published GHCR image):
git pull && docker compose pull app && docker compose up -d appPrebuilt GHCR image:
docker pull ghcr.io/getappbox/middleware:latest && docker compose up -d appNative (do not run as root):
cd /opt/appbox-middlewaregit fetch && git pullgo build -trimpath -ldflags="-s -w" -o bin/middleware ./cmd/middlewaresudo service middleware restartAll configuration is environment variables, loaded from .env.<environment> and .env or passed through the environment by Compose/systemd. .env.example is the annotated reference for these settings:
| Variable | Purpose | Default |
|---|---|---|
PORT |
HTTP listen port | 8080 (fallback) |
APPBOX_CLIENT_TOKEN |
Shared secret for X-AppBox-Client-Token |
Required |
DROPBOX_APP_KEY |
Public OAuth client_id served by /api/v1/config |
- |
DROPBOX_TOKEN_CACHE_TTL_SECONDS |
How long a verified Dropbox token stays cached | 600 |
MAILGUN_API_KEY / MAILGUN_DOMAIN / MAILGUN_FROM |
Build-email delivery | - |
YOURLS_API_URL / YOURLS_SIGNATURE_SECRET |
Short-link backend | - |
SHORTLINK_TARGET_BASE |
Installer page the short link points at | - |
CORS_PROXY_ALLOWED_HOSTS |
Host suffixes /cors?url= may proxy to |
dropbox.com,dropboxusercontent.com,getappbox.com |
PROXY_MAX_BODY_BYTES |
Max bytes buffered from one proxied response | 4194304 (4 MiB) |
GITHUB_LATEST_RELEASE_URL / HOMEBREW_CASK_URL |
Update-check upstreams | - |
UPDATE_CACHE_TTL_SECONDS |
Update-check cache lifetime | 3600 |
NOTIFY_ALLOWED_HOSTS |
Host suffixes /api/v1/notify may POST to |
Slack + Teams hosts |
TRUSTED_PROXY_COUNT / TRUSTED_PROXY_CIDRS |
Right-side forwarded-IP hops for rate limits and YOURLS, with an optional immediate-proxy IP/CIDR allowlist | 1 / empty |
A missing /api/v1 secret is logged by name at boot but is not fatal. The install/appinfo/cors routes keep serving, and the affected /api/v1 endpoints return errors per request.
Authentication. Every /api/v1 route requires the static client token header. Shortening, mail and notification endpoints additionally require the caller's Dropbox access token as Authorization: Bearer <token>, server verifies it against Dropbox and caches the verdict by token digest for DROPBOX_TOKEN_CACHE_TTL_SECONDS. Only real, logged-in AppBox users can use the short links, send mail, or fire notifications.
Errors. Most /api/v1 failures return this envelope:
{ "error": { "code": "snake_case_code", "message": "Human readable detail." } }| Code | Status | Meaning |
|---|---|---|
invalid_client_token |
401 | Missing/incorrect X-AppBox-Client-Token |
missing_dropbox_token / invalid_dropbox_token |
401 | Bearer token absent or rejected by Dropbox |
invalid_body |
400 | Body did not decode into the expected shape |
invalid_recipients |
400 | Not 1–100 valid email addresses |
invalid_service |
400 | service was not slack or teams |
invalid_url |
400 | Malformed URL in the request body |
webhook_not_allowed |
403 | Webhook host not on NOTIFY_ALLOWED_HOSTS |
rate_limited |
429 | Bucket exhausted. See Retry-After |
misconfigured |
500 | A required env var is unset |
verification_unavailable |
503 | Dropbox verification outage (fails closed, uncached) |
shortener_unavailable / mail_provider_error / notify_failed / update_check_unavailable |
502 | Upstream provider failed |
Rate limits. Fixed window, per client IP, in-memory (single instance). Exceeding a bucket returns 429 with a Retry-After header.
| Bucket | Limit |
|---|---|
/api/v1/config |
120 / min |
/api/v1/latest-version |
120 / min |
/api/v1/shorten |
60 / min |
/api/v1/mail/send |
20 / min |
/api/v1/notify |
60 / min |
| Install / appinfo / cors routes | 300 / min |
/corshost allowlist: restricts allowed upstream hosts.PROXY_MAX_BODY_BYTES: caps proxied upstream bodies (default 4 MiB).- Self-sweeping token cache: removes expired, unread Dropbox token verdicts and caps cache entries.
If AppBox has been useful to you, consider supporting its continued development.
Thank you for supporting open source! 🙏