Set up a core instance¶
This page takes you from an empty directory to a live core: Forgejo, Infisical, a runner, logs, Pages and backups.
1. Render the repository¶
Answer the prompts:
| Prompt | Meaning | Example |
|---|---|---|
instance_slug |
Permanent identity for every derived name | quiet-heron |
tailnet_dns |
Tailnet DNS suffix | example.ts.net |
server_tailnet_ip |
Host's tailnet address | 100.64.0.10 |
admin_emails |
Comma-separated admin emails | ops@example.com |
forgejo_admin_user |
First Forgejo account | operator |
forgejo_admin_email |
First Forgejo email | ops@example.com |
infisical_admin_email |
First Infisical email | ops@example.com |
backup_bucket |
Object-store bucket | lairkit-core |
backup_endpoint |
S3 endpoint | https://s3.example.com |
backup_region |
S3 region | us-east-1 |
notify_channel |
Alert channel | webhook |
notify_url |
Alert destination | https://… |
The render lands in lairkit-core-<slug>/. Commit it before running anything that mutates.
2. Finish the console steps¶
Three things have no API and are done once, by a named person.
| Step | Where | What to keep |
|---|---|---|
| Tailscale API key | Tailscale admin → Settings → Keys → Generate access token | TS_API_KEY |
| Object store | Provider console → bucket → Access keys; enable versioning | S3_ACCESS_KEY, S3_SECRET_KEY |
| DNS | Tailscale admin → DNS → enable MagicDNS and HTTPS certificates | Nothing; confirm certificates can issue |
The Forgejo admin password is generated for you. Do not create it in a browser.
./lk check preflight --tailnet and ./lk check preflight --store prove the first two steps. The store check uploads a scratch object, reads it back byte-for-byte and deletes it.
3. Collect facts and secrets¶
collect is the only prompting command. It:
- fills any remaining placeholder in
config/instance.yml; - stores
TS_API_KEYand the S3 pair in.kamal/bootstrap.env(mode0600, gitignored); - generates the backend passwords and tokens;
- commits the tree and, if there is no remote, creates a local bare remote at
.git/lk-origin.git.
The escrow record is printed once by install setup (or by ./lk run), not by collect.
To script it, export the three values and skip the prompts:
Escrow before the first mutation
The escrow record contains values that cannot be recreated, including the Forgejo and Infisical encryption material. Store it offline before running ./lk run. install setup refuses to start without the acknowledgement.
4. Run the install¶
run performs the bring-up in the only order that works on a fresh tailnet:
| Stage | What happens |
|---|---|
preflight |
Tools, facts, host and object store are checked before anything mutates |
net |
Tailnet policy is applied, the host is tagged, the CI tag is created, four Services are advertised |
setup |
Forgejo config is rendered, the escrow record is printed once, then one kamal setup --skip-push boots the ten accessories and waits for readiness |
admin |
Forgejo admin, org, teams, runner, Infisical project and identities, demo site |
ops |
Host backup/restore bodies, cron, first backup, first drill, Operations issue |
verify |
Four service checks |
Each stage is a separate dispatch with its own lock, evidence tag and exit code. A stage that changes nothing returns 10 and the run continues. A red stage stops the run and prints the stage name and exit code.
run is idempotent. A second run changes nothing and exits 10.
Run the stages yourself¶
./lk check preflight --tools --facts --host
./lk install net --reason "first install"
./lk install setup --escrow-ack --reason "first install"
./lk install admin --reason "first install"
./lk install ops --reason "first install"
./lk check verify
5. Check the result¶
A healthy core reports live and prints the earliest credential expiry and one next: line. Then:
You should have four tailnet URLs:
| Service | URL |
|---|---|
| Forgejo | https://<slug>-forgejo.<tailnet_dns> |
| Infisical | https://<slug>-infisical.<tailnet_dns> |
| Dozzle | https://<slug>-dozzle.<tailnet_dns> |
| Pages | https://<slug>-pages.<tailnet_dns> |
The demo site is published at:
Sign in to Forgejo as forgejo_admin_user. The password is FORGEJO_ADMIN_PASSWORD in .kamal/bootstrap.env; copy it to your password manager.
The bootstrap file stays
.kamal/bootstrap.env is retained at mode 0600 because the database passwords, encryption keys, pgBackRest cipher and S3 pair must be readable while Infisical is down during a resume, reboot or restore. It is gitignored. Infisical remains the remote source of truth.
6. What is now running¶
| Part | Count |
|---|---|
| Tailnet node | 1 (the host) |
| Kamal accessories | 10 |
| HTTP Services | 4 |
| Facts file | 1 (config/instance.yml) |
| Secret store project | 1 (lairkit-core-<slug>) |
| Durable client state | 0 |
Troubleshooting¶
| Symptom | Code | Next |
|---|---|---|
| Dirty tree, wrong checkout or foreign lock | 2 |
./lk check status names the lock holder; clean or push the tree |
| Preflight red | 11 |
Read the failing line's remedy; nothing was mutated |
| Accessory crash-looping after setup | 1 |
./lk check incident, then ./lk change upgrade --component <name> --reason "repair a failed boot" |
| Tailnet policy preview differs | 2 |
Edit policy/tailnet.yml; nothing was applied |
| First backup failed | 1 |
The tag names the failing body; ./lk check backup prints the last error |
| Facts still show placeholders | — | Run ./lk collect again; check the line it names |
Do not re-run install setup to restart a stopped accessory. Setup does not restart an existing container; the repair path is change upgrade.