Ostiaby SolutionMAX

Docs

From install to
first cutover.

Everything on one page. Search it, or jump from the list on the left. The API contract and the full README live on GitHub.

Install

One command on any Linux host. Docker is installed when it is missing. Run it as root or through sudo.

curl -fsSL https://ostia.solutionmax.net/install.sh | sh -s -- \
  --brand "Your Mail" --admin you --domain mail.yourhosting.example
FlagWhat it does
--brand "Name"Product name shown in the console, on status pages and in emails. Change it later under Branding.
--admin userUsername of the first administrator. Default admin.
--password pwPassword for that account, at least 8 characters. Generated and printed once when omitted.
--domain hostPublic hostname; sets the console URL to https. Put a reverse proxy with TLS in front, or use --port on a LAN.
--port 8410Port on the host. Default 8410.
--dir /opt/ostiaWhere the compose file and .env live.
--version 1Image tag to follow. 1 follows the 1.x line, 1.0.0 pins a release.
--uninstallStops and removes the containers. The data volume stays until you remove it yourself.

Running the same command again upgrades in place and keeps .env. Requirements: Docker, 1 GB RAM for the default three parallel syncs. See the README for the plain compose route.

First login

Open the URL the installer printed and sign in with the admin account. Under Team you can add operators, require a six digit second factor, and create read only accounts. Under Deploy & API you create tokens for scripts and billing systems.

Customers

A customer groups mailboxes, one migration project and one backup plan, and owns a status page. Add one from Customers, or let the New migration drawer create it on the way.

  1. Customers, Add customer: name, mail domain, contact address, notes, colour.
  2. Every mailbox you add later is attached to this customer, to its migration or to its backup plan.
  3. Removing a customer removes its projects, plans and mailboxes. Removing a project or plan keeps the mailboxes.

Migrations

A migration is one project per customer move: a source server, a destination server, a cutover moment and a nightly delta time. It moves through four phases on its own.

  1. Initial copy. The first full copy while the old server stays live. Phase 2 starts when every mailbox has finished at least one run.
  2. Nightly delta. Only new mail, every night at the delta time.
  3. Final cutover. Reached at the cutover moment. Switch DNS, run Sync all now for the last delta.
  4. Verified. Every mailbox passed the verification pass: folder counts match on both sides. Send the report.

Add mailboxes one at a time (source login, destination login, ports) or in bulk. Each mailbox has its own drawer: skip folders, cap the message size, an own schedule, the folders with their progress, the live log and the run history. Actions on a selection: Sync now, Full resync, Verify, Pause, Edit settings, Remove.

Port and TLS: 993 is IMAP over TLS, 143 is plain or STARTTLS. Ostia passes the port to imapsync; imapsync picks TLS on 993 by itself.

Bulk CSV

Paste lines or choose a .csv file in the Add mailboxes drawer. The header row is optional.

source_user,source_pass,dest_user,dest_pass
[email protected],Sx91k2,[email protected],Nk22p9
[email protected],Qw34l7,[email protected],Lm55r1

dest_user may be empty: the source address is used. Server and port for all rows are set once in the drawer. Every row gets a login test before anything is copied; rows that fail are added as Failed with the reason and the rest start right away.

Backups and restore

A backup plan mirrors each attached mailbox to a server you control, every night, every six hours or weekly, and keeps deleted mail for the retention you set. After each pass a verification run counts the folders.

  1. Backups, New backup plan: customer, target server and port, repeat, time, retention days.
  2. Add mailboxes to the plan; the destination is the same address on the backup server unless you fill in another.
  3. Run now on the plan or on one mailbox whenever you like. Migrations keep priority in the sync slots.
  4. Restore from the Actions menu of a protected mailbox: whole mailbox or only what is missing, to the original address or any other. Nothing is deleted on the target; duplicates are skipped.

Status pages

Every customer has a public link /s/<token>: your logo, the phase, progress, cutover date, a live line of what is being copied, their mailboxes with plain statuses, and three short answers. No servers, credentials, logs or errors. Copy or regenerate the link from the customer page.

Branding

Settings, Branding: product name, tagline, logo (PNG, SVG or JPEG up to 200 KB), accent colour, support address and phone, and the switch that hides the powered by line. Applies to the console, status pages, reports and emails at once. The installer's --brand seeds the name on the first start.

Microsoft 365 and Google Workspace

Both switched password logins off for IMAP. Register once per tenant under Settings, Mail providers, then choose that credential as the sign in method on the mailbox or project.

Microsoft 365

  • An application in Entra ID with the application permission IMAP.AccessAsApp, admin consent granted.
  • Ostia needs the tenant ID, client ID and client secret. One token is fetched for the whole tenant.

Google Workspace

  • A service account with domain wide delegation for https://mail.google.com/.
  • Ostia needs the service account address and its private key.

Tokens are minted per run and written to a 0600 file on tmpfs that imapsync rereads when it reconnects, so a long run survives a token that expires halfway.

Updates

The console checks OSTIA_RELEASES_URL (Check now, or in the background) and shows the release notes. Install when syncs finish, or Install in the window, hands the request to the updater sidecar. The sidecar pulls the image, swaps the container, waits for the health check, rolls back to the previous image on failure, and writes the result into the history. While an update is pending no new syncs are admitted so the engine goes idle. A manual path always works: docker compose pull && docker compose up -d in the install directory.

API

Create a token under Deploy & API (read, or read and write) and send it as a bearer token. The full contract is in docs/OSTIA-API.md.

curl -X POST https://mail.yourhosting.example/api/customers \
  -H "Authorization: Bearer ost_live_..." -H "content-type: application/json" \
  -d '{"name":"Bakery BV","domain":"bakery.example","contact":"[email protected]"}'
curl -X POST https://mail.yourhosting.example/api/mailboxes/bulk \
  -H "Authorization: Bearer ost_live_..." -H "content-type: application/json" \
  -d '{"customer_id":"<id>","project_id":"<id>","host1":"imap.oldhost.example","port1":993,
       "host2":"mail.yourhosting.example","port2":993,"start":true,
       "rows":[{"user1":"[email protected]","pass1":"...","user2":"[email protected]","pass2":"..."}]}'

Environment

VariableMeaning
OSTIA_KEY32 bytes, base64. Encrypts mailbox passwords and stored credentials. Keep it with the backup of the volume.
OSTIA_PASSWORDPassword of the first administrator on an empty install.
OSTIA_ADMINUsername of that administrator. Default admin.
OSTIA_URLPublic URL of the console, used in emails and for secure cookies.
OSTIA_MAX_PARALLELSync slots. Default 3. Raise together with the memory limit.
OSTIA_RETENTION_DAYSHow long run logs are kept. Default 30.
OSTIA_RELEASES_URLWhere the update check reads the release manifest.
OSTIA_UPDATER_TOKENShared secret between the console and the updater sidecar.
OSTIA_BRANDSeeds the product name on the first start.
TZTimezone schedules are read in. Default Europe/Amsterdam.

Every MAILFLOW_* name from the 0.3 line still works as a fallback.

Troubleshooting

Could not reach the server

Check the port: 993 for IMAP over TLS, 143 for plain. Check that the Ostia host can reach the mail server at all (firewall, private network). The run log in the mailbox drawer shows the exact imapsync error.

The login was refused

Wrong password, or the server wants an app password or OAuth. For Microsoft 365 check that admin consent was granted for the tenant; the Mail providers page shows Revoked when a token can no longer be minted.

Update pull failed

The host could not fetch the new image from the registry. The old image stays in place and the history says so. Try docker compose pull in the install directory to see the registry error.

Verification says short

The destination has fewer messages than the source in some folders. Common causes: messages over the size cap, duplicates the engine skipped, or a folder the destination does not accept. Open the run log for the folder list.