Self-host it (fully free)
i18n-keyless is one product, and you can run it yourself: the same API, the same dashboard,
the same MCP server as i18n-keyless.com — it is the very Docker image we run — on your
own machine, with your own database and your own AI provider.
The source is public, under the Elastic License 2.0: github.com/ambroselli-io/i18n-keyless-server. Read it, build the image yourself, or send a pull request.
Fully free: unlimited projects, all 48 languages, unlimited translations, the dashboard, the MCP server, every SDK, no expiry. Nothing to buy, nothing to enter but your own AI key.
If you like it, consider a donation at
https://i18n-keyless.com/self-hosted — any amount from 1 to 1 million dollars. The product is fully available without it. A donation
gives you a licence key (starts with ik1.) that silences the donation prompt in the
dashboard.
With ONCE (recommended)
ONCE is 37signals' open source tool for running Docker apps on your own server: one line to install, then a terminal console for the domain, the TLS certificate, updates and backups. i18n-keyless follows its conventions, so it is a first-class app there.
On a fresh Linux server:
curl -fsSL https://get.once.com | sh
once
In the console, add an app, enter the image path, and the host name you want it on:
ghcr.io/ambroselli-io/i18n-keyless:latest
ONCE pulls the image, starts it, and takes care of DNS and TLS. Open the host name in your browser:
- Create your account. The first account of an instance is its admin: it creates projects and invites people.
- Choose the AI provider and paste your key at that provider, on the Settings screen you land on. Test the key asks the provider once before you save.
- Create your project. No licence needed — projects are unlimited.
That is the whole install. The dashboard says when the instance is ready, and what is still missing until then.
With docker compose
No ONCE? One file and Docker:
mkdir i18n-keyless && cd i18n-keyless
curl -fsSL https://i18n-keyless.com/self-hosted/docker-compose.yml -o docker-compose.yml
docker compose up -d
open http://localhost:1800
Then the same steps in the browser: the admin account, the AI key, your project.
Put your usual reverse proxy (Caddy, nginx, Traefik) with TLS in front of port 1800 first if you can: the instance learns its public URL from your first sign-in. Moved it later? The Settings screen has the URL too.
Settings: the dashboard, or the environment
The licence, the AI provider and the public URL live on the dashboard's Settings screen
(admins only), and are kept in /storage/settings.json, next to the database and inside
the backup. A change applies at once, no restart.
Each of them can also be set in the environment — an .env next to docker-compose.yml
(the example), or ONCE's
Settings → Environment form. A value from the environment wins, and the Settings
screen shows it read-only with the variable's name. Use that to lock a setting, or to
script an install; leave it out and the dashboard is enough.
The AI provider
Translations are made by the model you choose, on your own account. Any provider the Vercel AI SDK knows — pick it on the Settings screen, or name it in the environment:
AI_PROVIDER | AI_MODEL (default) | Note |
|---|---|---|
mistral | mistral-small-latest | What i18n-keyless.com runs on. |
openai | gpt-4o-mini | |
anthropic | claude-haiku-4-5-20251001 | |
google | gemini-2.0-flash | |
openai-compatible | llama3.1 | Ollama, Groq, Together, a proxy… set AI_BASE_URL (default http://localhost:11434/v1). |
AI_API_KEY is the key at that provider. A whole app costs cents.
When the provider refuses
A wrong key, no credits left, a model that does not exist: the provider refuses, and new texts stay untranslated — your app shows them in its source language, as always. Nothing reaches your users, not even in the browser console. Instead:
- the dashboard shows a red banner to the instance's admins, and Settings → AI provider shows what the provider said;
- if you set a webhook in Settings → Alerts (or
ALERT_WEBHOOK_URL), the instance POSTs one message when the refusals start and one when translations work again. Slack and Discord webhooks, an ntfy.sh topic (a free push to your phone), or any URL that takes a JSON body. Send a test alert checks it before you save.
These refusals are yours to fix, so they are not reported to the maintainers' Sentry.
Accounts and projects
- The first account created on an empty instance is the admin. Admins create projects
and can make other users admin (
PUT /user/admin). - Everyone else uses the projects they are invited to. When you add a member, the dashboard shows the invitation message to send them yourself (with the set-password link); the instance sends no email, so there is no mail provider to configure.
- Pausing a project (admins) stops its key; nothing is deleted.
Point your app at your server
Every SDK takes an API_URL. Add it next to the key:
import * as I18nKeyless from 'i18n-keyless-react';
I18nKeyless.init({
API_KEY: 'your-project-key',
API_URL: 'https://i18n.example.com', // your APP_URL
storage: window.localStorage,
languages: { primary: 'en', supported: ['en', 'fr', 'es'] },
});
The dashboard's snippets already carry it. Node, Vue, Angular and the browser package take
the same option; Laravel, Rails and Flutter read it from their own config. The MCP server is at
https://i18n.example.com/mcp, and the onboarding screen prints the claude mcp add line.
Upgrade, back up
ONCE updates and backs up from its console. With compose: docker compose pull && docker compose up -d;
the schema is applied at boot and the volume is kept. The data lives in /storage:
i18n-keyless.db (SQLite: users, projects, translations), settings.json (the AI key, the
URL, the licence if you bought one) and secret (signs the sessions). Copy the volume and
you have everything.
Prefer Postgres? Set DATABASE_URL=postgresql://…; the image ships both drivers.
The instance does not update itself (ONCE excepted) and does not tell you a new version exists. To hear about the ones that matter, see below.
Product updates by email
Settings → Product updates: give an address to get notified of important updates — security updates, bug fixes. A few emails a year, no marketing. You confirm it with a link we email you (nothing is sent before), and every email has a link to unsubscribe. The address goes to the maintainer of i18n-keyless and nowhere else.
What your instance sends us
At each start, one request to api.i18n-keyless.com/self-hosted/ping with:
- a random install id, made once and kept in
/storage/.install-id; - the version;
- how it runs:
once,docker,kubernetes,podmanorother; - the database kind (
sqliteorpostgres, never the URL); - the AI provider's name (never the key);
- the CPU architecture and the Node version.
We look up the country of the request's IP (through country.is) and do
not keep the IP. TELEMETRY=off stops this ping. The product-update address, if you gave one,
is sent too, and still is with TELEMETRY=off: you asked for it. Error reports are
SENTRY_KEY's, below.
What is different from the hosted product
Nothing in the software: it is the same image. What differs is who operates it.
| Hosted | Self-hosted | |
|---|---|---|
| Price | Per project, per month | Fully free, donations optional |
| Machine, database, AI account | Ours | Yours |
| Projects | One per subscription, created from the website | Unlimited, created by your admin |
| Support | Email, best effort |
Environment reference
Nothing is required: the first five are the Settings screen's, and a variable only locks
the value. The instance boots and answers its health check (GET /up) with none of them.
| Variable | On the Settings screen | Default | What it does |
|---|---|---|---|
LICENSE_KEY | yes | — | Your licence key from a donation, and it is optional. Verified offline. The product is fully free without it; the key only silences the donation prompt in the dashboard. |
AI_PROVIDER | yes | mistral | See the table above. |
AI_MODEL | yes | the provider's default | |
AI_API_KEY | yes | — | Your key at the provider. |
AI_BASE_URL | yes | — | For openai-compatible, or a proxy. |
ALERT_WEBHOOK_URL | yes | — | Where to POST when the AI provider refuses, and when it works again. |
APP_URL | yes | learnt from the first sign-in | The public URL: cookie security, OAuth issuer, invitation links. |
DATA_DIR | — | /storage | Where settings.json, secret and the SQLite file live. |
DATABASE_URL | — | file:/storage/i18n-keyless.db | SQLite file, or a Postgres URL. |
SECRET | — | generated once, kept in /storage (ONCE's SECRET_KEY_BASE is honoured) | JWT secret of the dashboard sessions. |
TELEMETRY | — | on | off stops the start-up ping described above. |
SENTRY_KEY | — | the maintainer's | Where errors are reported. By default they reach us, the maintainers — that is how bugs get fixed. off disables it; your own DSN redirects it. |
Lost your licence key?
Write to us with the email you bought it with. There is nothing to revoke or renew: a licence is bound to that email and is valid forever.