Skip to content

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.

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:

kubectl -n astrolift get ingress
# Add an A/CNAME for app.astro.example.com -> the ingress address

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.

  1. Plugin: Vanilla Kubernetes.
  2. Paste the kubeconfig for the tenant cluster. Use a service-account kubeconfig scoped to the namespaces Astrolift manages, not your personal admin context.
  3. Name the cluster and submit.
  1. Plugin: AWS.
  2. Provide the cluster name, region, and the IAM role ARN the control plane should assume (IRSA / cross-account role).
  3. 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.

  1. Kind: GitHub OAuth App config.
  2. OAuth Client ID and OAuth Client Secret: paste from your GitHub OAuth App.
  3. OAuth redirect URI: must exactly match the callback URL you registered on GitHub:
    https://app.astro.example.com/app/auth1/scm/github/callback
    

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.

  1. Project: pick one (create a project on /projects first if you have none — apps live inside a project).
  2. Name + slug: the slug is your stable identifier and is immutable after this.
  3. Source: choose Connected host, pick your GitHub connection, and select the repo. The form auto-fills the clone URL, kind, and default branch.
  4. Manifest path: leave as astrolift.toml (the default).
  5. 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:

astro deploy --app my-first-app

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:

build image → push to registry → render manifests → apply → wait healthy → assign URL

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>/environments lists the public URL per environment.
  • From the CLI: astro app status --app my-first-app.

Verify it's actually up:

curl -I https://my-first-app.astro.example.com/health
# HTTP/2 200

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 .env on /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.