Self-hosting: overview and prerequisites¶
Read this before installing anything. It says what a Winner AI installation is made of, what the server and your organisation must provide, and every connection that leaves your network. Installing the Winner AI server is the install itself.
Three things decide whether you can install today:
- Sign-in is through an OpenID Connect provider over https: Auth0, or the one your organisation already runs, such as JumpCloud.
- A publicly trusted certificate for the server's names, in one of two modes. Either the internet reaches the server on 80 and 443, where the certificate authority checks each name, or, for a server only a private network or VPN reaches, the names sit in an Amazon Route 53 public zone and the server has an AWS instance role that may write their challenge record.
- One linux/amd64 server with Docker. Nothing else is supported.
What you run¶
Winner AI has no hosted service. Each organisation runs its own installation: one server that holds the organisation's coding-agent sessions, signs its people in through its identity provider, and serves the Dashboard and the product pages to its Managers. A client on each developer's laptop sends that laptop's sessions straight to the server's database. Nothing of ours connects to the server. We build and sign the releases and answer support; you run everything else.
The database holds every session your developers' coding agents ran: their prompts, the agents' replies and the tools they called. Protect the server and its disks as you would a source repository.
| Part | What it does |
|---|---|
| Edge | Stock Caddy. Terminates https on 443 for the server's names, and on 80 redirects to https and, in the http certificate mode, answers the certificate authority. |
| Sign-in gate | Stock oauth2-proxy. Every page passes it and signs in through your identity provider, apart from the few addresses that are public by design or that a laptop calls with its own token. |
| Web server | Stock Caddy with one pinned plugin, behind the gate on every request: it routes to the control plane and the dashboard, admits only the installation's Managers to the dashboard, and brands its pages. |
| Control plane | Our application: sign-in landing, the roster, laptop enrollment, the organisation's schema and database roles, the product pages, Settings, and these guides at /guide/. |
| Jobs service | The same application's background passes: Prompt Coaching, Skills, Benchmarks, role sync, the sampling of which laptops pushed, and the heartbeat. |
| Dashboard | The session dashboard Managers open from the control plane: browse, search and read every session of the organisation. Its container runs agentsview pg serve. |
| Database | Postgres with pgvector. The archive of every session; laptops push to it over TLS on 5432. |
| Certificate helpers | db-certs hands Postgres the certificate for its name; in the dns mode, dns-certs (stock lego) obtains and renews the certificate through Route 53, and edge-reload tells the edge when it changes. |
| AI runner | Stock Ollama, on by default (the local-llm profile in COMPOSE_PROFILES). Serves the embedding model and, unless you point them elsewhere, the model calls. It runs models on CPU. |
| Laptop client | winner and the session collector (agentsview) on each developer's laptop. Laptop client guide covers it. |
How the data moves¶
laptop (agentsview pg push) ──5432, TLS──> database (the organisation's schema)
laptop (winner) ──443──> edge ──> sign-in gate ──> web server ──> control plane (enrollment, reports)
browser ──443──> edge ──> sign-in gate ──> web server ──> control plane, dashboard ──> database
sign-in gate, control plane ──> your identity provider
control plane, jobs, dashboard ──> AI runner, or your hosted model endpoint
A laptop sends its sessions straight to the database, as a database role that belongs to that one laptop and reaches its organisation's schema and nothing else. The control plane is not in that path: it enrolls the laptop and hands it the role, and laptops keep pushing while it is down.
The supported shape¶
One linux/amd64 server running Docker Compose, installed from the release bundle. Before installing anything, the installer refuses anything but Linux on x86-64, and a Docker daemon that is not linux/amd64. It builds nothing on the server: the control plane's, the Dashboard's and the sign-in gate's images come out of the bundle, and the other public ones are pulled from Docker Hub at fixed, checked versions.
Not supported: an arm64 server, a container service such as Amazon ECS, Kubernetes or another orchestrator, and an installation spread over several servers. Laptops on arm64 are supported; only the server is amd64.
What you operate¶
- The server and its operating system: updates, disk, monitoring, and where the server runs.
- Hardening. Winner AI ships no firewall rule, jail or filter, and nothing on a bundle install checks which ports the server publishes.
- Admit only 80, 443 and 5432 from outside, plus your own administration
access. Docker's own rules publish container ports past host firewalls
such as ufw and firewalld, so set the rule in your network or cloud
firewall, or in Docker's
DOCKER-USERchain, then check from outside that only those three answer. - 5432 is open to wherever laptops connect from, so anyone there can guess passwords against it. Only per-laptop roles are admitted from outside; banning an address after repeated refused logins slows guessing. A fail2ban jail reading the database container's log that bans after five refused logins in ten minutes, for an hour, is a starting point. Never ban the stack's own subnet (below), and give an address many laptops share (a VPN or an office's NAT) a far higher count: one laptop with a stale password writes about two refused logins a minute, and would lock out everyone behind that address (The Postgres jail).
- DNS and the certificate: the server's names and their records.
- The identity provider: who may sign in, and who is a Manager.
- The model endpoint, if you use a hosted one, and its key.
- Backups. The bundle ships the backup and restore commands, but nothing on a bundle install schedules a backup or copies one off the server.
- Upgrades. Nothing upgrades itself: Upgrade and roll back says how to install one.
- Telemetry: off unless you switch it on (Model endpoint and telemetry).
Prerequisites¶
Everything below is needed before the install. The model endpoint is optional.
The server¶
- linux/amd64 (x86-64), Ubuntu, with Docker Engine 28.0 or later and the Docker Compose plugin 2.24.4 or later. The host check the install runs refuses an older one, and a Docker daemon that is not linux/amd64. Check the requirements says how to install them.
- A user who can run
docker, who runs the install. ssh-keygen(OpenSSH),sha256sumandtar, to check and unpack the bundle,opensslandcurl, for the install's secrets and checks, andss(theiproute2package), for the host check's ports; Check the requirements has the versionssh-keygenmust be.- Disk. 5 GB free where Docker keeps its data, 15 GB with the AI runner, plus room for the unpacked bundle. No CPU or memory figure has been measured yet. The database grows with your team's sessions, and the AI runner, which runs models on CPU, is the heaviest service.
- Ports 80, 443 and 5432 free on the server, and a clock within 5 seconds of the real time, kept by time sync, which the host check compares.
- No network of its own at
172.16.86.0/24. The stack pins that subnet for its own containers, and the database admits every role, its superuser included, from inside it. The server's networks, routes and any VPN range laptops connect from must not use it. - Outbound https to Docker Hub (the install fails if a pull does), your
identity provider's issuer (the sign-in gate does not start without it), a
public certificate authority, the Route 53 API in the
dnscertificate mode, and the Ollama registry while the AI runner is on. What leaves the server lists every destination by name.
DNS, certificate and ports¶
- A public DNS name for the server, and one for the database (it may be
the same name), resolving to it from wherever your people and laptops are.
Use names, not IP addresses;
scripts/check-env.shrefuses an IP address for the database's name. - A certificate mode (
CERTIFICATE_MODE), which decides how the certificates are taken over ACME. The edge presents one for each name, and the database presents its name's, so laptops verify it against their system trust store. http, the default: 80 and 443 reachable from the internet, for both names. The certificate authority connects to the server on 80 or 443 to check each name.dns, for a server nothing on the internet reaches: both names in an Amazon Route 53 public zone, and an AWS instance role on the server that may write the challenge record in it. The certificate authority reads a TXT record instead of connecting to the server, so no inbound port is needed for the certificate. Network says which mode to choose, and Private VPC: the certificate through DNS the role's policy.- 5432 reachable from every laptop, which pushes there over TLS: from the internet, or only from your office and VPN ranges if every laptop connects from them.
- An e-mail address for the certificate account (
ACME_EMAIL).
Sign-in¶
A production installation signs in through any OpenID Connect provider
whose issuer is https: Auth0, or the provider your organisation already runs.
scripts/check-env.sh, which the installer runs, refuses an issuer that is not
https, and a provider other than Auth0 while Auth0 Management credentials are
set.
On a provider other than Auth0, the provider needs an application for the
sign-in gate, and the Managers are a group at the provider or a list of
addresses in .env; the Auth0 settings hold placeholders and the Management
credentials stay blank.
Connect your identity provider is the checklist, and
JumpCloud: before the install a worked example.
On Auth0, the tenant needs:
- one organisation for the installation, with sign-in requiring it and without adding people to it at sign-in;
- the post-login Action, which puts the roles and the organisation on each sign-in and refuses a sign-in to the gate through any other organisation, with its two secrets set to the installation's values;
- a regular web application for the sign-in gate, with the server's callback and logout addresses;
- a native application with the device-code grant and offline access,
which only a
winnerolder than the control plane's own laptop sign-in uses: a currentwinnersigns in through the control plane; - with Auth0 Management credentials, which let Admin add people and read
roles from Auth0, a machine-to-machine application for the Management
API and the roles
managerandmember: with the credentials set, the control plane does not start without the roles.
Who may sign in,
Fill in .env and
The post-login Action say how each is
set, and Configuration lists every
setting.
A model endpoint¶
None is required. The AI runner in the bundle serves the embedding model and, by default, every model call. To use a hosted model for the rest, you need an OpenAI-compatible endpoint over https and its key, or Amazon Bedrock; Model endpoint and telemetry says what the endpoint must support, how to check it before switching Prompt Coaching on, and why the AI runner keeps serving embeddings (Embeddings).
From Winner AI¶
- The release bundle,
winner-ai-server-<X.Y.Z>.tar.gz, and the release key's fingerprint, which you confirm with your Winner AI contact over a different channel from the bundle; Verify the bundle's signature prints the one to confirm. - A licence file. A Manager uploads it on Settings, which checks it from the file alone, never with us. Until one is uploaded, the deployment runs 30 days of grace from its first start. Licence covers installing and renewing it.
What leaves the server¶
These are the connections Winner AI's software on the server makes, as read
from its code; no capture of a running stack has been run yet. Your operating
system's own traffic (package updates, time, your cloud provider's services)
and any copy of a backup you set up are yours, and not listed. Every
connection is outbound https, on 443 unless an address you set (the model
endpoint, the heartbeat or a telemetry host) names another port. Three
exceptions. Two are plain http on 80. When the edge's certificate names an OCSP
responder, the edge fetches the certificate's revocation status from that
address. And on AWS, whatever signs with the server's instance role reads
the role's credentials from the instance metadata service at the link-local
address 169.254.169.254: Amazon Bedrock signed with the instance role, the
certificate helper in the dns mode, and scripts/check-dns-zone.sh and
scripts/env-from-secrets.sh when you run them. The third is DNS on UDP
port 53: scripts/check-dns-zone.sh, run before the first dns-mode start,
asks the public zone's own name servers for its test record directly. The
certificate helper itself needs no outbound port 53.
| Destination | When | Why |
|---|---|---|
Your identity provider's issuer, <OAUTH2_PROXY_OIDC_ISSUER_URL> (on Auth0, <AUTH0_DOMAIN>) |
Always | The sign-in gate reads its configuration, tokens and keys. On Auth0, the control plane also checks an older winner's Auth0 token against its keys and, with Management credentials, calls its Management API for the roles, the roster, enrollment and role sync. |
A public ACME certificate authority: Let's Encrypt (acme-v02.api.letsencrypt.org), and ZeroSSL (acme.zerossl.com, and api.zerossl.com for its account credentials) when Let's Encrypt fails |
At first start and around each renewal | The certificates. In the http mode the authority also connects in to 80 or 443 to check each name; the dns mode uses Let's Encrypt only. |
| The Route 53 API | Around each issue and renewal, in the dns mode |
The certificate helper writes the challenge record, signing with the server's instance role. |
Docker Hub: registry-1.docker.io, auth.docker.io, and the storage host it redirects image data to |
At install and upgrade, and when you run scripts/check-dns-zone.sh |
The installer pulls the public images: the database, the edge and web server base, the certificate helper in the dns mode, and the AI runner while local-llm is on. The zone check looks up the certificate helper's image. Docker Hub limits pulls without a login per outbound address. |
ghcr.io, GitHub's registry |
At install and upgrade, when trial is in COMPOSE_PROFILES |
The trial's sign-in provider (Dex), pulled by digest. |
The Ollama registry, registry.ollama.ai, and the storage host it redirects model data to |
At every AI runner start, while local-llm is on |
The runner pulls the embedding model, and the chat model when an endpoint points at the runner. |
| Your hosted model endpoint, and any endpoint a Manager sets for the organisation on Settings | When one is set | Prompt Coaching, Skills, Benchmarks and the dashboard's insights. What each feature sends to the model lists what each sends. |
raw.githubusercontent.com, openrouter.ai |
When the control plane sets up the organisation's schema: at first start (twice when the first attempt fails), at every later start until one succeeds, after an upgrade that changes the collector version, and when a Manager runs the migration from Admin | Setting up the schema refreshes the model prices that cost figures use. There is no switch for it, and laptops make the same refresh. |
FLEETVIEW_HEARTBEAT_URL |
After every jobs sweep, when you set it | Your own dead-man's switch. |
| The error-report and analytics hosts you set | Only when you switch telemetry on | Telemetry lists each kind and every field it sends. |
Allow the two redirect storage hosts by the names your proxy or firewall logs for them: they are content-delivery hosts whose names and addresses change.
There is no licence check-in and no update check. The Dashboard runs with its usage ping and update check switched off, and the control plane sets up schemas with the usage ping off.
Two other parties see traffic because of the installation, not from the server:
- People's browsers load fonts from Google Fonts (
fonts.googleapis.com,fonts.gstatic.com): Archivo and JetBrains Mono on the control plane's pages, and Archivo on the dashboard. These guides serve their own. - Laptops reach the control plane, the database and a few hosts of their own; What the laptop sends, and where lists them.