Self-host 60-second tour
Before you set aside an afternoon for the full install, take sixty seconds to see what self-hosting Polaris Express actually looks like. This page is not a tutorial — it is a tour. It shows you the shape of the system, what you will run, and what you will need on hand. When you are ready to install for real, jump to the prerequisites page.
What you are deploying
Section titled “What you are deploying”Polaris Express is five components. Three of them run on infrastructure you control:
Directoryexpresscharge/
Directoryweb/ Deno + Fresh fullstack app (admin + customer UI, API, SSE)
- …
Directorysteve/ SteVe OCPP backend — your ChargeBoxes connect here
- …
Directoryemail-worker/ Cloudflare Worker for transactional email
- …
Directoryios/ Native iOS app (you do not host this)
- …
Directorydocs/ This site (you do not host this)
- …
The web app, a Postgres database, and a sync worker run together as
one Docker Compose stack. SteVe runs as its own stack — your chargers
talk to it over WebSocket. The email worker is deployed to Cloudflare
(it is not in the Compose stack).
What the integrated stack looks like
Section titled “What the integrated stack looks like”The root docker-compose.yml brings up four services:
| Service | What it does |
|---|---|
postgres | Postgres 17, holds all application state |
migrate | One-shot — runs deno task db:migrate then exits |
app | The Fresh web app, exposes port 8000 |
sync | Background worker that reconciles SteVe ↔ web ↔ Lago |
Once it is up, you curl localhost:8000/healthz and you are looking
at your own copy of Polaris Express.
Sixty seconds, end to end
Section titled “Sixty seconds, end to end”-
Clone the monorepo
Terminal window cd expresschargeThe
--recursiveflag pulls all five submodules. If you forget it,make bootstrapwill fix it. -
Fill in web/.env
The whole stack reads
web/.env. You will set database credentials, the SteVe WebSocket URL, BetterAuth secrets, and (optionally) Lago and Cloudflare email-worker URLs. The full reference is on the environment variables page. -
Bring it up
Terminal window make upThis runs
docker compose upagainst the rootdocker-compose.yml. First boot pulls images, buildsweb/from its Dockerfile, runs migrations, and starts the app and sync worker. -
Stand up SteVe separately
SteVe is its own Docker stack inside
steve/. It needs its own Postgres and its own config. Your chargers will point at SteVe’s WebSocket endpoint; the web app will point at SteVe’s REST API. -
Deploy the email worker
From
email-worker/, runnpx wrangler deploy. Then setCF_EMAIL_WORKER_URLinweb/.envto the deployed worker URL. Without this, magic link emails will not send.
What you need on hand before you start the real install
Section titled “What you need on hand before you start the real install”- A Linux host with Docker and Docker Compose. 4 GB RAM is enough for a small site.
- A domain name and the ability to set DNS records. The web app, the SteVe WebSocket, and the email worker each need their own hostname.
- A TLS terminator in front of the stack (Caddy, Traefik, or a cloud
load balancer). The Compose stack exposes plain HTTP on
:8000. - A Cloudflare account for the email worker, plus an email-sending provider (Resend, Postmark, or SES) that the worker will call.
- Optional — a Lago instance if you want metered billing. Polaris Express works without it; you just lose the billing surface.
Verify the tour, not the install
Section titled “Verify the tour, not the install”This page does not install anything. To check that you can at least clone the repo and that Docker is healthy:
cd /tmp/expre-tour && docker compose configdocker compose config prints the resolved Compose file. If it errors
on a missing web/.env, that is expected — you have not filled it in
yet. If it errors on Docker itself, fix that before proceeding.
If something feels wrong
Section titled “If something feels wrong”- “I do not want to run SteVe.” You have to. SteVe is the OCPP endpoint your chargers connect to. There is no hosted alternative.
- “Can I skip the email worker?” Only if you are happy with no user signups, no magic link logins, and no transactional email. For any real deployment, no.
- “Can I skip Lago?” Yes. Leave the Lago env vars unset and the billing surface will be inert. Sessions and charging still work.
Next phase
Section titled “Next phase”Ready to do it for real? Start with
prerequisites — the checklist of accounts,
DNS records, and host requirements you will want lined up before
the first make up.