Journal indexDockup / field note
Note / self-host-metabase

How to Self-Host Metabase in 2026: Application Database, TLS and Backups

A practical Metabase self-hosting guide covering Docker, ports, persistent data, TLS, security, backups and the failures that block production use. With checks.

If you already tried to self-host Metabase, the frustrating state is probably familiar: the UI appears, but the application database is missing even though dashboard source databases remain. Recreating the container rarely fixes a disagreement between URLs, state and dependencies.

This walkthrough uses one concrete completion criterion — connect a read-only sample database, save a question, build a dashboard and deliver a subscription through the configured mail channel. Every configuration choice is evaluated against that criterion rather than against a green container badge.

Credentials, roles and exposed surfaces

Threat-model the action Metabase performs, not just its login form. Here the high-risk mistake is using the embedded H2 application database as the only production copy. Implement this boundary: give Metabase read-only database roles where possible and separate collection permissions from database credentials.

Generate MB_ENCRYPTION_SECRET_KEY once, keep it out of Git and preserve it with the recovery manifest because changing it can invalidate encrypted or signed application state. Do not solve a permission error by running the container as root or mounting the host broadly. Resource limits also belong to the security design when JVM heap, concurrent queries, result caching and load transferred to each analytics data source can be triggered by users.

Separate Metabase from its dependencies

The smallest responsible Metabase topology contains one private listener on 3000, an ingress route and a documented state boundary. The network contract for Metabase is a dedicated Postgres application database separate from analytics sources. Keep private endpoints on internal DNS, permit only required outbound calls and give Metabase a scoped service credential.

Validate the topology by asking a clean client to connect a read-only sample database, save a question, build a dashboard and deliver a subscription through the configured mail channel. Watch JVM heap, concurrent queries, result caching and load transferred to each analytics data source while it runs. The result tells you whether the next improvement belongs in memory, storage, networking or a separate worker instead of encouraging arbitrary container sizing.

A Docker baseline for Metabase

The following command makes the container boundary visible without pretending to provision every external service.

docker run -d \
  --name metabase \
  --restart unless-stopped \
  -p 127.0.0.1:3000:3000 \
  -v metabase-data:/metabase-data \
  -e MB_ENCRYPTION_SECRET_KEY=replace-with-a-long-random-value \
  -e MB_DB_TYPE=h2 \
  -e MB_DB_FILE=/metabase-data/metabase.db \
  metabase/metabase:latest

Before opening ingress, inspect the resolved environment, mounts and listener. Add the reviewed connection settings for a dedicated Postgres application database separate from analytics sources; use private names for private services. A successful launch ends when you can connect a read-only sample database, save a question, build a dashboard and deliver a subscription through the configured mail channel, not when docker ps prints Up.

Prove the Metabase deployment end to end

A production gate for Metabase should be executable by someone who did not build the deployment. Give that person the pinned version, a non-sensitive test account and this task: connect a read-only sample database, save a question, build a dashboard and deliver a subscription through the configured mail channel. If the instructions require undocumented shell access, the service is not yet operationally ready.

Repeat the gate after replacing only the container. Then restore the Metabase application database, not only queried data sources into blank infrastructure and prove that users, collections, questions, dashboard filters and subscriptions reappear and execute against the restored connection metadata. Measure JVM heap, concurrent queries, result caching and load transferred to each analytics data source during both successful runs; unexpected differences often reveal a missing cache, index, worker or data mount.

Add a failure drill: temporarily deny the test identity access to a dedicated Postgres application database separate from analytics sources. Metabase should emit a useful error, preserve existing state and recover when the valid condition returns. Save the timestamps and relevant log lines, with secrets redacted. That evidence becomes the reference for the next image or configuration change.

Keep internal and external URLs straight

The browser, API client and Metabase must agree on one origin. To make that true, set MB_SITE_URL to the public HTTPS origin. Preserve the original host and protocol while keeping port 3000 unavailable as a competing public address.

The site-down troubleshooting guide helps distinguish an unreachable route from a responding application. That distinction matters here: the application database is missing even though dashboard source databases remain. Only the former is fixed by ingress changes; the latter needs Metabase logs, state or workload inspection.

Operate Metabase around its real bottleneck

For Metabase, monitor a transaction rather than a process: connect a read-only sample database, save a question, build a dashboard and deliver a subscription through the configured mail channel. Combine its latency and error rate with JVM heap, concurrent queries, result caching and load transferred to each analytics data source so an alert identifies the constrained component.

The upgrade rehearsal must cover that the Metabase application database and plugin versions must migrate together; queried business databases are not a substitute for that state. Restore, migrate and run the transaction before production replacement. If the application database is missing even though dashboard source databases remain, do not erase data to make startup green; compare version, variables, mounts and dependency reachability in that order.

Volumes are only the first recovery layer

Protect Metabase's state before optimizing its container. The required set is the Metabase application database, not only queried data sources. Mount /metabase-data before bootstrap, write harmless sample data and replace the container to prove that path is actually persistent. If multiple stores must agree, document the order in which writes are paused and backups are taken.

Keep copies outside the deployment server and encrypt material containing credentials or private content. Recovery succeeds when users, collections, questions, dashboard filters and subscriptions reappear and execute against the restored connection metadata. The distinction between a persistent mount and an independent copy is covered in persistent storage and snapshots.

Deploy Metabase on Dockup without losing its boundaries

A Dockup template should encode the image, port 3000, mounts, health timing, domain, TLS and secret delivery. Dockup should keep private portions of a dedicated Postgres application database separate from analytics sources on internal networking and expose no extra public port. The same deployment can target Dockup servers or customer-attached capacity.

After the route is live, apply the public setting and try to connect a read-only sample database, save a question, build a dashboard and deliver a subscription through the configured mail channel. Back up the Metabase application database, not only queried data sources and keep the restore exercise in the operating plan; those are Metabase responsibilities that remain visible after infrastructure provisioning.

Frequently asked questions

What does Metabase need for a production deployment?

Route the Metabase container on port 3000 through one HTTPS origin. The supporting network requirement is a dedicated Postgres application database separate from analytics sources. Do not call Metabase ready until you can connect a read-only sample database, save a question, build a dashboard and deliver a subscription through the configured mail channel.

Which Metabase data belongs in a backup?

Persist /metabase-data and include the Metabase application database, not only queried data sources in the same recovery manifest. A clean Metabase restore passes only when users, collections, questions, dashboard filters and subscriptions reappear and execute against the restored connection metadata.

Does Metabase require HTTPS behind a reverse proxy?

Use HTTPS for the public Metabase origin and keep port 3000 on the internal route. Apply the Metabase setting correctly: set MB_SITE_URL to the public HTTPS origin. For Metabase, HTTPS protects credentials or user content in transit and keeps origin-sensitive client behavior consistent.

How should a Metabase upgrade be tested?

Restore current Metabase state into an isolated deployment, apply the candidate version and repeat its acceptance transaction. Pay particular attention because the Metabase application database and plugin versions must migrate together; queried business databases are not a substitute for that state. Keep the previous Metabase image until its data-migration and rollback boundary are understood.