Server modePostgres + central auth
Multi-team, JWT-verified via JWKS. The webapp validates tokens offline against your auth server's /api/auth/.well-known/jwks.json.
Everything you need to install, configure, deploy and maintain i18n Dashboard โ whether you're a solo developer or an enterprise team.
The official image arnaudprioul/i18n-dashboard ships on Docker Hub for both linux/amd64 and linux/arm64. Three ways to run it depending on your team size.
Single user, single team. Translations live in a Docker volume. Best for self-hosting up to ~100k keys. Save this as docker-compose.yml and run docker compose up -d:
127.0.0.1 only by default: reachable from this machine, not from other devices on your network. Local mode has no login screen, so anyone who can reach the port would have full access to every project โ widen this binding only behind a firewall or VPN you already trust.Full quickstart, env vars and troubleshooting on the Docker Hub overview.
Multi-team, JWT-verified via JWKS. The webapp validates tokens offline against your auth server's /api/auth/.well-known/jwks.json.
Native macOS / Windows / Linux build with embedded Nitro server and SQLite. No Docker, no database to configure. Signing in goes through your account online.
Eight groups: getting started, framework guides, deployment, administration, quality, reference, billing and support.
Email verification & password reset.
Google, DeepL, Claude, Gemini, Mistral, LibreTranslate.
Admin, Moderator, Translator. Signed in through your central account.
Slack, Discord, GitHub Action, GitLab CI.
JSON backup, merge/replace import, CLI commands.
Every runtimeConfig value is overridable at runtime via the NUXT_* prefix โ Nitro's canonical convention. Bare names like I18N_DB_HOST are silently ignored unless explicitly listed as wire-protocol vars.
The full reference (every variable, default, scope, and migration note) lives on the Docker Hub page where it stays close to the image:
Open the full env var reference on Docker Hub โI18N_APP_MODE โ local / server / desktop. Server mode requires a real DB and a central auth.NUXT_DB_CLIENT + NUXT_DB_HOST + NUXT_DB_NAME + NUXT_DB_USER + NUXT_DB_PASSWORD โ Postgres / SQLite / MySQL connection.NUXT_SESSION_SECRET โ required in production. Generate with openssl rand -hex 32.NUXT_CENTRAL_AUTH_URL + NUXT_PUBLIC_CENTRAL_AUTH_URL โ server-side and browser-side URLs of your auth issuer (must be JWKS-compatible).NUXT_AUTH_JWT_ISSUER + NUXT_AUTH_JWT_AUDIENCE โ expected iss / aud claims on access tokens.NUXT_INTERNAL_API_SECRET โ shared HMAC for webapp โ central-auth side calls. Must be identical on both sides.NUXT_SMTP_HOST + NUXT_SMTP_PORT + NUXT_SMTP_USER + NUXT_SMTP_PASS + NUXT_SMTP_FROM โ workflow notifications. Leave host empty to disable email.NUXT_DASHBOARD_URL โ the public URL of this webapp instance, used in transactional email links.Pick any SMTP relay and pass the four values below โ the image will deliver email through it on every workflow event.
For local dev / smoke testing, point to the bundled Mailpit service: NUXT_SMTP_HOST=mailpit, NUXT_SMTP_PORT=1025.
A role is granted per project, not instance-wide โ three tiers, each unlocking more of what that project allows.
translator | moderator | admin | super_admin | |
|---|---|---|---|---|
| Edit translations | Yes | Yes | Yes | Yes |
| Approve translations | No | Yes | Yes | Yes |
| Manage project (settings, scan, sync) | No | No | Yes | Yes |
| Manage project members | No | No | Yes | Yes |
Assign a role from a project's Users page โ pick a member, then translator, moderator, or admin. An admin on one project has no power over any other project, or over the account that owns it.
super_admin sits outside every project role โ an account-level flag that bypasses every check above, on every project. It is granted automatically to the first account created on an instance, whether through the local setup wizard or the first sign-in in server mode, and there is currently no way to promote another account to super_admin from inside the dashboard.
Configured per project from Admin โ Integrations (super_admin only). Each webhook posts to your endpoint whenever a subscribed event happens on that project.
A webhook can subscribe to any of the following:
key.deleted โ one or more translation keys were deletedtranslation.saved โ a translation value was savedscan.completed โ a source-code scan for new or changed keys finishedsync.completed โ a sync with the configured translation provider finishedEvery delivery to a generic HTTP endpoint carries X-Webhook-Signature โ an HMAC-SHA256 of the JSON body, using the secret shown once when the webhook was created โ and X-Webhook-Event. Slack and Discord endpoint URLs are detected automatically and receive that platform's own message format instead; those two authenticate via the URL itself, so they never carry a signature header.
https: โ plain HTTP is only tolerated outside production.https://user:pass@host) are rejected.Use the โถ button next to a webhook to send a signed ping event on demand, without waiting for a real one.
super_admin only, from Admin โ Backup or the CLI. A backup is a single JSON export covering every project, translation, user, and setting.
Always excluded: refresh_tokens, password_reset_tokens, otp_tokens, webhook_deliveries, and every account's password hash.
"Download backup" saves a dated JSON file, e.g. i18n-dashboard-backup-2026-07-31.json.
Restoring uploads that file back and asks for a mode:
The result reports rows restored, duplicates skipped, and any row that failed, rather than silently reporting success on a partial restore.
Both commands need an elevated admin token โ NUXT_CLI_ADMIN_TOKEN (falling back to NUXT_CLI_TOKEN) โ passed with --token, or resolved from your CLI config.
The issues self-hosters run into most, straight from the Docker image's own troubleshooting guide.
Refusing to start: NUXT_DB_HOST is still the build-time default 'localhost' โ your environment still uses pre-NUXT_* names. Add the NUXT_ prefix to your DB env vars (NUXT_DB_HOST, NUXT_DB_USER, โฆ).Webapp returns 401 on every API call โ the JWKS endpoint isn't reachable. Check that NUXT_CENTRAL_AUTH_URL resolves from inside the container (use the Docker network hostname when both services run in the same compose).JWT verification fails right after a key rotation โ the JWKS cache lives 1 hour and refreshes 30 seconds after a key-id miss. Give it a short grace period, or restart the webapp right after rotating.Health check shows "0 keys" despite a non-empty database โ you're probably hitting the wrong database. Confirm NUXT_DB_HOST is actually set, rather than falling back to a leftover SQLite file.Container starts on port 3000 instead of 6001 โ Nitro reads PORT directly. The image sets I18N_PORT=6001, but overriding PORT moves the bind โ keep it aligned with your ports: mapping.Can't reach the dashboard from another machine โ expected with the default Compose snippet โ the port binds to 127.0.0.1 on purpose. Bind a routable address, or put a reverse proxy in front, to expose it deliberately.