# RustBox Docker Run all commands from the `docker/` directory. Most Compose files use the project name `rustbox`; the HA/Garage example uses `rustbox-ha`. The examples pass `-p` explicitly so an exported `COMPOSE_PROJECT_NAME` cannot attach RustBox to an unrelated Compose project/network. ## Quick start Two RustBox nodes + Envoy + Valkey + PostgreSQL + OpenSearch + Garage S3: ```bash PORT=3009 \ IMAP_HOST=mail.example.com \ SMTP_HOST=mail.example.com \ docker compose -p rustbox-ha -f compose-ha-garage.yml up --build ``` Verify load balancing and the selected backend header: ```bash curl -sSI http://localhost:3009/ | grep -i '^x-rustbox-backend:' curl -sSI http://localhost:3009/ | grep -i '^x-rustbox-backend:' ``` PostgreSQL + S3/SILO + OpenSearch: ```bash PORT=3009 \ IMAP_HOST=mail.example.com \ SMTP_HOST=mail.example.com \ docker compose -p rustbox -f compose-postgres-s3-opensearch.yml up --build ``` SQLite, local blobs and local Tantivy: ```bash IMAP_HOST=mail.example.com \ SMTP_HOST=mail.example.com \ docker compose -p rustbox -f compose-single-sqlite.yml up --build ``` MySQL + NFS + OpenSearch: ```bash NFS_SERVER=10.0.0.10 \ NFS_EXPORT=/exports/rustbox \ IMAP_HOST=mail.example.com \ SMTP_HOST=mail.example.com \ docker compose -p rustbox -f compose-mysql-nfs-opensearch.yml up --build ``` Check only the RustBox project: ```bash docker compose -p rustbox -f compose-postgres-s3-opensearch.yml ps ``` Stop it without deleting persistent volumes: ```bash docker compose -p rustbox -f compose-postgres-s3-opensearch.yml down ``` To also delete the Compose volumes, use `down -v` only when you really want to remove local database, S3 and OpenSearch data. ## Environment variables Copy the supplied template if you prefer a persistent local configuration: ```bash cp .env.example .env ``` | Variable | Default | Used by | Description | |---|---|---|---| | `HOST` | `0.0.0.0` | all | Address RustBox listens on inside the container. | | `PORT` | `3001` | all | Published HTTP port. Single-node examples also use it as the RustBox listener; HA keeps RustBox on `3001` internally and maps `${PORT}` to Envoy `8080`. | | `IMAP_HOST` | `mail.example.com` | all | IMAP server hostname used for mailbox access/authentication. Set this for a real mail system. | | `IMAP_PORT` | `993` | all | IMAP server port. | | `SMTP_HOST` | `mail.example.com` | all | SMTP server hostname used for sending mail. | | `SMTP_PORT` | `587` | all | SMTP submission port. | | `TLS_ENABLED` | `true` | all | Enables TLS for mail connections according to RustBox configuration. | | `RUST_LOG` | `warn,rustbox=info,tower_http=info` | all | Rust logging filter. Keeps dependencies quiet by default; use explicit target directives for dependency debugging. | | `SESSION_ENCRYPTION_KEY` | development key | PostgreSQL, MySQL | Shared key used to encrypt session data. All application nodes must use the same value. Replace it outside local testing. | | `POSTGRES_PASSWORD` | `rustbox-dev-password` | PostgreSQL | Password for PostgreSQL user `rustbox`; also used in `DATABASE_URL`. | | `S3_ACCESS_KEY` | `rustbox` | PostgreSQL/S3 | Access key for the bundled S3-compatible SILO service and RustBox S3 client. | | `S3_SECRET_KEY` | `rustbox-s3-dev-password` | PostgreSQL/S3 | Secret key for SILO and RustBox S3 client. Replace it outside local testing. | | `MYSQL_PASSWORD` | `rustbox-dev-password` | MySQL/NFS | Password for MySQL user `rustbox`; also used in `DATABASE_URL`. | | `MYSQL_ROOT_PASSWORD` | `rustbox-root-password` | MySQL/NFS | MySQL root password used by the container and health check. | | `NFS_SERVER` | none | MySQL/NFS | NFS server address. Required for `compose-mysql-nfs-opensearch.yml`. | | `NFS_EXPORT` | `/rustbox` | MySQL/NFS | Export path on the NFS server. | | `GARAGE_ACCESS_KEY_ID` | development key | HA/Garage | Garage S3 access key imported by the one-shot initializer. Replace outside local testing. | | `GARAGE_SECRET_ACCESS_KEY` | development secret | HA/Garage | Garage S3 secret key. Replace outside local testing. | | `GARAGE_CAPACITY` | `10G` | HA/Garage | Capacity assigned to the single Garage node for layout balancing. | | `SIEVE_ENABLED` | `false` | HA/Garage | Enables ManageSieve routes/UI on both RustBox nodes. | | `DIAGNOSTICS_ENABLED` | `true` | HA/Garage | Enables diagnostics routes/UI. | | `ABOUT_ENABLED` | `true` | HA/Garage | Enables the About panel; keyboard shortcuts stay available independently. | | `SECURITY_HEADERS_ENABLED` | `false` | HA/Garage | Enables RustBox browser security headers. | | `COMPOSE_PROJECT_NAME` | `rustbox` in `.env.example` | Compose | Compose project name. A value exported in the shell overrides the file's `name:`. The documented commands use `-p rustbox`, which has the highest priority. | `RUSTBOX_CONFIG` and `DATABASE_URL` are set by the Compose files themselves and normally should not be supplied from the shell for these bundled topologies. ## Avoiding another Compose project If `docker compose ... ps` shows containers from another application, inspect the effective project-name override: ```bash printf 'COMPOSE_PROJECT_NAME=%s\n' "${COMPOSE_PROJECT_NAME:-}" docker compose -p rustbox -f compose-postgres-s3-opensearch.yml ps ``` For RustBox use `-p rustbox` in operational commands. This isolates service discovery too: the RustBox container resolves PostgreSQL as `postgres` only on the RustBox Compose network. Useful DNS/database checks: ```bash docker compose -p rustbox -f compose-postgres-s3-opensearch.yml \ run --rm --no-deps --entrypoint getent rustbox hosts postgres docker compose -p rustbox -f compose-postgres-s3-opensearch.yml \ exec postgres pg_isready -U rustbox -d rustbox ``` ## Topologies ### `compose-ha-garage.yml` Runs two RustBox application containers behind Envoy round-robin load balancing. PostgreSQL stores account/application state, Valkey stores shared sessions, OpenSearch provides the shared search index, and Garage provides S3-compatible blob storage. Only Envoy publishes a host port; the application nodes stay internal. Envoy adds `X-RustBox-Backend` with the selected upstream address to every proxied response. WebSocket upgrades are enabled and Envoy health-checks `/api/health` on both nodes. The example uses a fixed Docker subnet because Garage advertises its RPC address; change `172.28.80.0/24` in both the Compose file and `configs/ha-garage.toml` if it conflicts with your network. Garage is a single storage node in this local example. The application tier is redundant, but the backing services are not an HA production cluster by themselves. ### `compose-single-sqlite.yml` Single RustBox node with SQLite, filesystem blob storage and local Tantivy search. Persistent application data is stored in the `rustbox-data` Docker volume. ### `compose-postgres-s3-opensearch.yml` Cluster-ready backing topology with PostgreSQL, SILO providing an S3-compatible API, and OpenSearch. The RustBox application container itself has no persistent `data_dir` volume. The bundled SILO topology is intended for local/integration validation of the S3 API. Production deployments should use a security-reviewed S3-compatible service with an appropriate lifecycle and HA policy. ### `compose-mysql-nfs-opensearch.yml` MySQL, shared POSIX/NFS blob storage and OpenSearch. The NFS volume driver is deliberate: a normal local Docker named volume is not shared between Docker hosts and therefore is not a valid blob backend for a multi-host RustBox deployment. These examples intentionally run one RustBox application container; the shared backing services demonstrate storage/database topology, not multi-app load balancing. ## Production notes Replace all example passwords, S3 credentials and `SESSION_ENCRYPTION_KEY` before production use. The OpenSearch examples disable its security plugin to keep the local Compose topology self-contained. Production should use TLS/authentication and HTTPS URLs in `search.urls`. The PostgreSQL/SILO and MySQL/NFS examples intentionally start one RustBox application container. `compose-ha-garage.yml` demonstrates two application nodes sharing SQL, sessions, blob storage and search behind Envoy. For production, make the backing PostgreSQL/Valkey/OpenSearch/Garage services appropriately redundant and terminate TLS before or at the load balancer. ## Sessions and HTTP/HTTPS Docker Compose defaults to `ENVIRONMENT=development`. In this mode session cookies do not carry the `Secure` attribute, so login works when RustBox is opened directly over plain HTTP, for example `http://localhost:3009`. For a production deployment behind HTTPS set: ```bash ENVIRONMENT=production docker compose -p rustbox -f compose-postgres-s3-opensearch.yml up -d --build ``` For the HA example, expose Envoy only behind HTTPS/TLS termination and use: ```bash ENVIRONMENT=production docker compose -p rustbox-ha -f compose-ha-garage.yml up -d --build ``` In `production`, RustBox intentionally marks authentication cookies as `Secure`. Opening the application directly over plain HTTP in that mode causes the browser not to send the session cookie and protected requests return `Invalid or expired session`. After changing from production/HTTP to development/HTTP, log in again. If the browser still has stale RustBox state, clear cookies/site data for the RustBox origin once and reload. ## OpenSearch disk watermark / 429 errors The `opensearch-data` named volume still consumes space on the filesystem used by Docker. Running OpenSearch in a container does not give it an independent disk. If the Docker host filesystem reaches OpenSearch's flood-stage threshold, OpenSearch protects indices with `read_only_allow_delete` and RustBox indexing receives HTTP 429 responses. Check the actual filesystem seen by the container: ```bash docker compose -p rustbox -f compose-postgres-s3-opensearch.yml exec opensearch \ df -h /usr/share/opensearch/data ``` Also inspect Docker usage on the host: ```bash df -h docker system df docker volume inspect rustbox_opensearch-data ``` Free disk space first. Do not permanently lower the OpenSearch flood-stage safety threshold. If the index remains read-only after disk usage is back below the high watermark, clear the block explicitly: ```bash docker compose -p rustbox -f compose-postgres-s3-opensearch.yml exec opensearch \ curl -fsS -X PUT http://localhost:9200/rustbox-messages-v1/_settings \ -H 'Content-Type: application/json' \ -d '{"index.blocks.read_only_allow_delete":null}' ``` RustBox 0.2.8 retains the OpenSearch outbox backoff introduced in 0.2.2, so these 429/flood-stage responses no longer produce one warning per queued event on a full disk.