Files
RustBox/docker/README.md
T
Mateusz Gruszczyński e4aa787e06
RustBox CI / rustbox (push) Canceled after 0s
0.2.4
2026-10-31 22:36:28 +01:00

10 KiB

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:

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:

curl -sSI http://localhost:3009/ | grep -i '^x-rustbox-backend:'
curl -sSI http://localhost:3009/ | grep -i '^x-rustbox-backend:'

PostgreSQL + S3/SILO + OpenSearch:

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:

IMAP_HOST=mail.example.com \
SMTP_HOST=mail.example.com \
docker compose -p rustbox -f compose-single-sqlite.yml up --build

MySQL + NFS + OpenSearch:

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:

docker compose -p rustbox -f compose-postgres-s3-opensearch.yml ps

Stop it without deleting persistent volumes:

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:

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 info all Rust logging filter/level.
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:

printf 'COMPOSE_PROJECT_NAME=%s\n' "${COMPOSE_PROJECT_NAME:-<unset>}"
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:

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:

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:

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:

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:

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:

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.4 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.