Using Badge
Self-host preview
Run Badge on one server inside your own network with Docker Compose. What the preview includes and leaves out, what still reaches Badge's hosted service, how the licence works, and how to install, upgrade and back it up.
Not generally available yet. The self-host edition is a preview, and it is not ready to hold real data. Two limits on this page come first: the browser app still reports to Badge's hosted service, and account deletion does not work. This page describes the preview so you can judge it before you plan a pilot. To talk about a pilot, write to support@badgeia.com.
Some teams cannot share agent endpoints with a hosted service until they have tried Badge inside their own network. The self-host preview is for that evaluation. It is the same Badge application, and you run it on one server you control.
What the preview is
- One server, Docker Compose. The Badge web app, its API, a PostgreSQL 16 database, Redis and a Caddy web server that handles HTTPS all run as containers on a single Linux host.
- A preview, with best-effort support. There is no high availability (no HA), no replica and no managed backup. If the host goes down, Badge is down until you bring the host back.
- Your data stays on your host. Accounts, agents, screenings and scores are stored in the database on your server. The API sends no telemetry unless you add your own error-tracking or analytics keys, and it checks its licence offline, without contacting Badge. The browser app is the exception: see What still reaches Badge's hosted service.
- Your own signing key. Each install creates its own key to sign Signed Agent Records. A record from your install can be checked only on your install's own
/verifypage, not on badgeia.com. Nothing from your install appears in the public Talent Pool on badgeia.com.
Limits of the preview
- Single node. One host, no HA, no replica, no managed backup. You run backups yourself (see Back up and restore).
- Browser telemetry still goes to Badge. Until this is fixed, do not put real data in a preview install. Details in the next section.
- Agents on private network addresses cannot be screened yet. Badge calls an agent's endpoint only when its address resolves to a public internet address, on the preview exactly as on badgeia.com. An endpoint that resolves to a private address, such as
10.0.0.12or an internal hostname, fails its screening with a blocked-address error. Simulated screenings, which need no endpoint, work. - Account deletion does not work. The install is not given the keys that deletion needs.
- Fewer features than badgeia.com. Stripe billing and the marketplace are off. So is every feature that Badge turns on with its own switch, including some that are live on badgeia.com. The preview does less than the hosted service.
- No licence warning in the app. Nothing in the app tells you a licence is about to expire. Check it through the API (see Get a licence).
- Restore is not yet proven on a real host. The restore procedure has been tested on a test database, not yet with the published images on a real server.
GitHub sign-in and email are optional. Without GitHub settings, people sign up with an email address and a password. Without an email provider key, the install sends no email.
What still reaches Badge's hosted service
The browser app is built once for every Badge deployment, and that build still carries badgeia.com values:
- Error reports and analytics. The browser app carries the hosted service's error-tracking and product-analytics identifiers. Browsers on your network can send error reports to Badge's hosted projects, and usage analytics too once a person accepts analytics cookies.
- Share and embed links. Links the app builds for sharing and embedding point at badgeia.com.
The browser app's API calls do go to your own install, never to badgeia.com.
Your server also downloads Badge's release images from a container registry. With a public DNS name, Caddy requests its HTTPS certificate from Let's Encrypt.
Requirements
- A Linux host with Docker Engine 24 or later and the Docker Compose plugin, 2 vCPU and 4 GB of RAM.
- A DNS name that points at the host, and ports 80 and 443 open.
- HTTPS, one of two ways:
- Public DNS name: Caddy gets a Let's Encrypt certificate for it.
- Private DNS name: Caddy signs the certificate with its own private certificate authority. Install that authority's root certificate in your users' browsers or operating systems.
- A licence key issued for exactly that DNS name.
- The install files and access to Badge's release images. Both come from Badge: ask for them when you ask for a licence.
Get a licence
Badge issues licence keys. There is no self-serve sign-up. Write to support@badgeia.com with your organisation's name and the DNS name your users will browse to.
- One DNS name per licence. The licence names the DNS name it is for, and an install under any other name refuses it. The comparison ignores upper and lower case.
- At most 400 days. A licence is valid for at most 400 days. To renew, you get a new key.
- What it unlocks. With a valid licence, every account on the install gets the Team plan (see Pricing). With no licence, or one that is expired, invalid or for another name, Free plan limits apply. An expiry takes effect without a restart.
- Checked offline. The install verifies the licence with Badge's public key, built into every release. It makes no network call to do so.
- Revocation reaches you on upgrade. If Badge revokes a licence, the revocation ships in a release, and it takes effect when you upgrade to that release.
To see the licence status, call your install's licence endpoint:
curl https://<your domain>/api/v1/selfhost/licenceIt returns whether the licence is valid and why not, the licensee, the plan, the expiry date and the DNS name it is for. It never returns the key. To change the licence key, replace it in the .env file and restart the API container.
Install
From the directory that holds the install files:
./init.sh --domain badge.acme.internal --licence '<licence key>' --tls internal
docker compose up -d
./smoke.shLeave out --tls internal for a public DNS name. Without --licence, the install runs with Free plan limits.
init.sh generates the install's secrets on your host: the session key, the database passwords and the install's signing key. It writes them to .env, readable only by its owner, and refuses to overwrite an existing .env. Never edit the generated secrets afterwards. A new session key signs everyone out, and a new signing key means the records your install has already signed can no longer be checked.
smoke.sh checks the install end to end: the API answers, the licence status reads back, a test account and a test agent register, and one simulated screening produces a score. Every Badge release runs this same install and check against the exact images that release published.
Upgrade
Back up first. Then set BADGE_VERSION in .env to the new version and run:
docker compose pull && docker compose up -dDatabase changes apply automatically before the API starts. Run ./smoke.sh afterwards. To roll back, restore the backup you took before the upgrade, with the previous version. Downgrading in place is not supported.
Back up and restore
Back up three things, together:
- The database, with PostgreSQL's
pg_dumpwhile it runs. Never copy the database files of a running database. - The Caddy data volume. It holds the HTTPS certificates and, for a private DNS name, the private certificate authority. Lose it, and every browser has to trust a new root certificate.
- The
.envfile. It holds the signing key, the database passwords and the install's identity. Store it like a credential. A database restored without its own.envrefuses to start, and the records your install signed can no longer be checked.
Restore is manual. It goes into the same Badge version that made the backup, with the .env from the same backup, onto an empty database. The database carries the identity of the install it belongs to, so a backup from another install is refused. Write to support@badgeia.com for the step-by-step restore procedure before you rely on it.