Operator Quickstart¶
Zero to a live URL in under ten minutes. This walks an operator who has never touched Astrolift from an empty cluster to a deployed app reachable on a public hostname.
It assumes you want the fastest path, not the production-hardened one.
For the full Terraform + Helm install with backups, observability, and
multi-environment toggles, see Installing Astrolift and the
runbooks in
astrolift-opscode.
For recovery procedures when a step here goes wrong, see the
Runbooks.
1. Prerequisites¶
Have these ready before you start. The clock starts after this list.
| What | Why | Check |
|---|---|---|
| A Kubernetes cluster (1.28+) you can reach | Hosts both the control plane and tenant apps in this quickstart | kubectl get nodes returns Ready |
| cert-manager installed on that cluster | Issues TLS certs for app hostnames; deploys hang without it | kubectl get pods -n cert-manager all Running |
| A domain (or subdomain) you control, with DNS you can edit | The platform assigns <app>.<your-zone> and validates certs against it |
You can add an A/CNAME and a TXT record |
| Cloud credentials (AWS/GCP/Azure) or a kubeconfig for the tenant cluster | How the control plane talks to the cluster it deploys onto | See step 3 |
| A GitHub OAuth App (Client ID + secret) | Lets you and your users connect repos without a shared bot account | See step 4 |
kubectl 1.28+, and either helm 3.16+ or Docker + Compose |
Installs the control plane | helm version / docker compose version |
If you don't have cert-manager yet:
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager --create-namespace \
--set crds.enabled=true
Local-only trial
To try the platform on your laptop with no cloud and no public DNS,
use the kind dev profile in
INSTALL-k8s-native.md
instead. You'll get a working control plane on http://localhost:3000
but no public TLS URL — fine for kicking the tires, not for this
walkthrough's "live URL" goal.
2. Install the control plane¶
The control plane is the API, the dashboard UI, and the Temporal workers. Pick one of the two paths.
Path A — Helm (recommended)¶
Create a minimal values.yaml. baseDomain is the only value with no
sane default — it must be a zone you control.
# values.yaml
baseDomain: astro.example.com # apps land at <app>.astro.example.com
ingress:
enabled: true
className: nginx # or "alb" on EKS — see the AWS runbook
host: app.astro.example.com # where the dashboard itself answers
# Bundled datastores. Fine for a trial; point at managed Postgres/Redis
# for production (see install.md).
postgresql:
enabled: true
redis:
enabled: true
auth:
# Used to derive the at-rest secret encryption key (HKDF) and sign
# sessions. Generate once; treat it like a root credential.
secretKey: "REPLACE_WITH_openssl_rand_-hex_32"
helm repo add astrolift https://charts.astrolift.dev
helm repo update
helm install astrolift astrolift/astrolift \
--namespace astrolift --create-namespace \
-f values.yaml
# Wait for the control plane to come up
kubectl -n astrolift rollout status deploy/astrolift-api
kubectl -n astrolift rollout status deploy/astrolift-ui
Point your dashboard host at the ingress, then open it:
Path B — Docker Compose (single host)¶
For a single VM with Docker. Create a .env:
# .env
ASTROLIFT_BASE_DOMAIN=astro.example.com
ASTROLIFT_HOST=app.astro.example.com
SECRET_KEY=REPLACE_WITH_openssl_rand_-hex_32
POSTGRES_PASSWORD=REPLACE_ME
# Default local Fernet secrets backend; swap to a cloud KMS for prod.
ASTROLIFT_SECRETS_BACKEND=local_fernet
curl -fsSL https://astrolift.dev/compose.yaml -o compose.yaml
docker compose --env-file .env up -d
docker compose ps # api, ui, worker, postgres, redis, temporal all Up
Open https://app.astro.example.com (or http://localhost:3000 if you
left the host unset). Create the first admin account when prompted — the
first user to sign up becomes the org owner.
3. Connect your cluster¶
The control plane needs a way to talk to the cluster it deploys apps onto. In the dashboard, go to Clusters → Register.
- Plugin:
Vanilla Kubernetes. - Paste the kubeconfig for the tenant cluster. Use a service-account kubeconfig scoped to the namespaces Astrolift manages, not your personal admin context.
- Name the cluster and submit.
- Plugin:
AWS. - Provide the cluster name, region, and the IAM role ARN the control plane should assume (IRSA / cross-account role).
- Submit. The platform resolves the EKS endpoint and CA via
describe_cluster.
After registering, run the Health check button on the cluster row. A healthy cluster reports the API reachable, cert-manager present, and an ingress controller detected. If it stalls or fails, jump to Runbooks → Cluster registration stuck before continuing — a deploy onto an unhealthy cluster will only fail later and more confusingly.
EKS + ALB
If you registered an EKS cluster and will use the AWS Load Balancer
Controller, registration sets manageBackendSecurityGroupRules=false
for you to avoid the dual-SG FailedNetworkReconcile trap. You don't
need to do anything; it's noted here so the value isn't a surprise in
your Helm diffs. See
Runbooks → ALB FailedNetworkReconcile.
4. Connect a source provider¶
Go to Settings → Source Providers and click Connect host.
- Kind:
GitHub OAuth App config. - OAuth Client ID and OAuth Client Secret: paste from your GitHub OAuth App.
- OAuth redirect URI: must exactly match the callback URL you registered on GitHub:
Save, then click Connect my GitHub on the new row and authorize the
app. GitHub redirects back and your account gains a
personal · <your-login> connection. Your repositories are now
selectable when registering an app.
The full GitHub setup — registering the OAuth App on GitHub's side, visibility scopes, and the error-code table — is in Connecting Astrolift to GitHub via OAuth.
5. Register your first app¶
Go to Apps → New.
- Project: pick one (create a project on
/projectsfirst if you have none — apps live inside a project). - Name + slug: the slug is your stable identifier and is immutable after this.
- Source: choose Connected host, pick your GitHub connection, and select the repo. The form auto-fills the clone URL, kind, and default branch.
- Manifest path: leave as
astrolift.toml(the default). - Deploy branch: your default branch.
Your repo needs an astrolift.toml at the root. The minimum that
produces a live HTTP app:
astrolift_version = 1
[app]
slug = "my-first-app"
repo = "github.com/you/my-first-app"
runtime = "python" # or node, go, etc. — drives buildpack autodetect
[[workloads]]
slug = "web"
public = true # public = true gets a hostname + ingress
[[workloads.containers]]
name = "web"
primary = true
port = 8000 # the port your process listens on
healthcheck = "http:/health" # path the platform probes for readiness
If you don't have one yet, astro app new --template python-web scaffolds
a working app with this manifest already in place.
Submit. The platform fires OnboardAppWorkflow, which provisions a
namespace, a registry repo, and workload identity for the app. The app
status moves pending → provisioning → ready. A failed status shows
the error inline on the app overview page.
6. Watch the first deploy¶
Trigger the first deploy from the app overview (Deploy button) or via the CLI:
Open the Deployments tab. The list polls and listens to a live subscription, so the in-flight rollout updates without a refresh. Click the row to follow the Lifecycle log — every workflow state transition appears as it happens:
A first deploy typically takes ~2–3 minutes (most of it the initial image build; subsequent deploys reuse cached layers and are faster).
Reading status:
- deploying — normal while building/rolling out. If it sits here past ~5 minutes, see Runbooks → App deploy stuck.
- succeeded — the new revision is healthy and serving.
- failed — expand the failed step in the lifecycle log; the error (image pull, crash loop, rollout timeout) points you at the matching runbook section.
7. Get your live URL¶
Once the deploy succeeds:
- The app overview hero shows an Open button — that's the primary
public URL,
https://my-first-app.astro.example.com. /apps/<slug>/environmentslists the public URL per environment.- From the CLI:
astro app status --app my-first-app.
Verify it's actually up:
If you get a TLS error or a 502/503, the cert challenge or the pod may still be settling — give cert-manager a minute, then check Runbooks → App deploy stuck → DNS not propagating.
That's zero to a live URL. The hard parts (cert issuance, ingress wiring, workload identity) were handled by the platform.
8. Next steps¶
- Secrets — set literals or import a
.envon/apps/<slug>/secrets. Managed-service connection vars (DATABASE_URL,REDIS_URL) show up automatically once a service is active. See Working with Apps → Secrets. - Environments — add staging/prod targets, set required-approval
counts, and pause/resume deploys per environment on
/apps/<slug>/environments. - Managed services — provision Postgres, Redis, or object storage from
/apps/<slug>/managed-services; the platform creates the upstream resource and injects the connection envelope. - Preview deployments — wire the GitHub webhook so each PR gets an ephemeral environment that's garbage-collected on merge/close.
- Production install — when you're past the trial, move off the bundled datastores and follow the full Installing Astrolift path with backups and observability.