Self-hosting Hinata#
Hinata is designed to be run by you, on your own infrastructure, with no seats, board or user limits. This page is the map: what pieces make up a running Hinata, how they fit together, and a checklist of everything you configure before going live. Each item links to a focused page with the concrete steps.
If you just want the fastest path to a running instance, start with the Quick start. This page is the bigger picture that production operators should read first.
What you run#
A production Hinata deployment is a small set of containers orchestrated by
Docker Compose. Two images are published to the GitHub Container Registry under
ghcr.io/hinata-platform; the rest are stock upstream images.
| Component | Image | Role |
|---|---|---|
| Server (API) | ghcr.io/hinata-platform/hinata-server |
Spring Boot 4 / Java 21 REST API under /api/v1, SSE live updates, JWT auth |
| Web app | ghcr.io/hinata-platform/hinata-app |
The compiled Flutter web client, served as static files |
| MongoDB | mongo:8.0 |
Primary data store — a replica set (2 data nodes + 1 arbiter) in production |
| Object storage | minio/minio |
S3-compatible store for attachments and avatars (presigned downloads) |
your SMTP relay (axllent/mailpit in dev) |
Outbound e-mail: verification, password reset, notifications |
The server is stateless — all state lives in MongoDB and MinIO — so you scale or redeploy it freely. Live updates reach clients over Server-Sent Events (SSE), so no extra message broker is required.
You do not need Firebase
Mobile push and universal (deep) links are relayed through the central Hinata Connect gateway. Your server registers itself with the gateway on boot; the published app's push credentials live in the gateway, not in your deployment. Self-hosters configure nothing for push.
The two Compose files#
The server repository ships two composable stack files. Think of the API stack as the base, and the app as an overlay you layer on top.
| File | What it brings up |
|---|---|
docker-compose.yml |
The full backend stack: the server, the MongoDB replica set (mongo1, mongo2, mongo-arbiter) and MinIO. This is the base. |
docker-compose.app.yml |
An overlay that adds the Flutter web app (hinata-app), served on HINATA_APP_PORT. Layer it on top of the base to serve the web client from the same host. |
Bring up the API stack alone:
docker compose up -d
Bring up the API stack and the web app together by passing both files:
docker compose -f docker-compose.yml -f docker-compose.app.yml up -d
You may not need to self-host the web app
Because native apps let a user save and switch between servers, and the web
build points at whatever API it is configured for, some operators run only the
API stack and let users reach it from the published apps. Serve the web app
yourself when you want a branded https://track.example.com in the browser.
There is also a third file for local development, docker-compose.dev.yml, which
starts only the infrastructure (Mongo, MinIO, Mailpit) so you can run the server
from your IDE. See Development.
Profiles: dev vs prod#
The server chooses its behavior from the Spring profile in
SPRING_PROFILES_ACTIVE:
prod— MongoDB is a TLS replica set with X.509 client authentication (no password in the connection string). This is whatdocker-compose.ymluses and what you deploy. The demo seeder is compiled out (@Profile("!prod")).dev— MongoDB runs standalone (still TLS + X.509) for a single developer onlocalhost. Used withdocker-compose.dev.ymlwhen running the server from source.
Never run the demo seeder in production
HINATA_DEMO_SEED=true populates a realistic English demo workspace (login
rebar / hinata-demo-2026) for screenshots and click-throughs. The seeder is
annotated @Profile("!prod"), so it is skipped entirely under the prod
profile regardless of the flag — but never rely on that as your only guard.
Leave HINATA_DEMO_SEED=false in every production .env. Seeding a live
instance would create a known-password admin and throwaway data in your real
database.
Configuration checklist#
Work through these before you expose the instance. Each links to the page with the concrete commands and file contents.
| Area | What to set | Page |
|---|---|---|
| Domain & TLS | Public hostnames, a reverse proxy terminating HTTPS, forwarding to HINATA_PORT (API) and HINATA_APP_PORT (web) |
Reverse proxy & TLS |
| JWT secret | HINATA_JWT_SECRET — a random ≥ 64-char HS512 secret (required in prod) |
Production deployment |
| MongoDB X.509 | Generate the PKI, register the client cert as the $external user |
MongoDB & X.509 |
| Object storage | MinIO credentials and bucket, or point at an external S3 | Object storage |
| SMTP | A real mail relay so verification / reset / notification mail is delivered | E-mail & SMTP |
| CORS | HINATA_CORS_ALLOWED_ORIGINS — the browser origins allowed to call the API |
Configuration reference |
| Trusted proxies | HINATA_TRUSTED_PROXIES — CIDRs of proxies allowed to set X-Forwarded-For |
Reverse proxy & TLS |
| Gateway | Usually the default; override HINATA_GATEWAY_BASE_URL only to run your own |
Hinata Connect gateway |
| First run | Complete the in-app setup wizard, or automate it with HINATA_SETUP_* |
Setup & first run |
For the exhaustive list of every environment variable — grouped, with defaults and whether each is required — see the Configuration reference.
Where to go next#
- Production deployment — the full, ordered walkthrough:
secrets, PKI, image tags,
up -d, health checks, DNS and the update flow. - Configuration reference — every setting, and the difference between env vars and runtime (database) settings.
- MongoDB & X.509, Object storage, E-mail & SMTP, Reverse proxy & TLS — the detailed per-subsystem pages.
- Backups & upgrades — keeping data safe across redeploys.