Skip to main content
Self-host Stackdome when you need direct infrastructure control, capacity that persists independently of Cloud alpha availability, or a platform your organization can adopt incrementally while keeping the same Stackfile and deployment workflow. stackdome-install takes one bare Linux server to a working dashboard and API, with local compute already connected. It also creates the platform database, an image registry, and an admin account you can sign in with. The installer runs unattended in numbered phases and waits for each component to become ready before moving on. This page covers the user-visible installation outcome first, then the infrastructure it creates and the exact installer controls.

Prerequisites

The installer runs a preflight check and refuses to continue unless all of the following hold. Two more things matter but are not enforced up front:
  • Ports 80 and 443 open for inbound traffic. After installing, the installer fetches http://<your-domain>/health and warns you if the dashboard is not reachable from the internet. Open them in your firewall or cloud security group beforehand and you avoid the warning.
  • Capacity. The installer warns, without stopping, if the server has fewer than 2 CPUs, less than 4 GB of RAM, or less than 20 GB of free disk on /. Treat those as the practical floor.

Flags

You need the stackdome-install binary built for your server’s platform — Linux on amd64 or arm64.
A public download for stackdome-install is not available yet. This page documents the flags and behavior of the installer; once downloads are published, this section will point you at them.
With the binary on the server, give it the execute bit and run it as root:
The install subcommand is optional for backward compatibility, but using it makes the operation explicit. The sudo is not optional. Without root the installer exits during preflight and tells you to re-run it with sudo. The GitHub flags are optional. Values you provide are stored in stackdome-bootstrap-secrets and reused by later upgrades; a later non-empty flag replaces its stored value. Everything else the installer needs — the database password, JWT signing secret, encryption key, and your admin password — it generates for itself.
The final summary prints your admin password once and tells you it will not be shown again. Copy it into your password manager before you close the terminal.

DNS

For a trial: nothing to do

Leave --domain off and the installer builds a domain from the public IP it detected: stackdome.203.0.113.10.nip.io for a server at 203.0.113.10. nip.io is a public DNS service that resolves any hostname containing an IP address straight back to that IP, so the name works the moment the installer picks it. No records to create, no propagation to wait for.

For a domain you own

Create an A record for the name you intend to pass to --domain, pointing at the server’s public IP, and let it propagate before you run the installer:
That one name carries two things. It is the dashboard URL you sign in at, and it is the base for the hostnames Stackdome generates for your applications, which sit below it and look like <generated-prefix>.<resource-name>.stackdome.example.com. Those application hostnames have to resolve to the same server, so a single A record for the dashboard is not the end of the DNS work.

Domains and TLS

The records to create for application hostnames, and how custom domains work once you are running.

What the install creates

On the server

  • A k3s pod limit, written as max-pods=250 in /etc/rancher/k3s/config.yaml when that file does not exist. If the file already contains a max-pods setting, the installer keeps it. If the file exists without one, the installer warns and does not overwrite it.
  • k3s, installed if the k3s binary is not already present, with Traefik disabled in the k3s installer because the Stackdome chart supplies routing. Its kubeconfig is /etc/rancher/k3s/k3s.yaml (mode 0600). If k3s is already installed, the binary installation is skipped; when the installer has just created the config above, it restarts k3s. It then waits up to two minutes for the node to report Ready.
  • Helm, installed if helm is not already on the PATH.

In the cluster

Namespaced installation resources land in stackdome-control-plane: the chart workloads, ServiceAccount and token Secret, bootstrap Secret, Volume, Stack, and StackResources. The installer also applies cluster-scoped resources: the chart’s CRDs, stackdome-api-server-role ClusterRole, stackdome-api-server-role-binding ClusterRoleBinding, and, for a real domain, the letsencrypt-prod ClusterIssuer. Those cluster-scoped resources do not belong to any namespace.
  • The stackdome-agent chart, installed from oci://quay.io/stackdome/charts/stackdome-agent at the version selected by --chart-version. Before upgrading, the installer server-side applies every CRD shipped by the chart. It then runs helm upgrade --install and waits for the chart and operator pods to be ready. If that exact chart version is already deployed, it skips the chart upgrade.
  • A bootstrap Secret, stackdome-bootstrap-secrets, holding the credentials the installer generated: the database password, the JWT signing secret, the encryption key, your admin password, plus your admin email and the domain.
  • RBAC for the API server: a stackdome-api-server-account ServiceAccount, the stackdome-api-server-role ClusterRole and binding, and the long-lived stackdome-api-server-account-secret token Secret. The role can manage Stackdome stacks, resources, volumes, users, registries, and Postgres addons; observe build and cluster status; create a cluster issuer and CNPG image catalogs; manage the namespaces and Secrets those workloads need; and read pods, logs, Services, nodes, and pod metrics.
  • A Volume, stackdome-db-data — 10Gi, ReadWriteOnce, storage class local-path — backing the platform database.
  • A Stack, stackdome-platform, grouping the two resources below.
  • A db StackResource running postgres:16-alpine on port 5432, not exposed publicly, with the volume mounted at /var/lib/postgresql/data.
  • An api-server StackResource running the image from --image. It runs database migrations as an init step, then serves on port 8000, exposed publicly at your domain.
  • A ClusterIssuer — only when you install on a real domain. See TLS below.
The installer then polls the API server’s /health endpoint for up to five minutes before continuing.
The API-server role is narrower than cluster-admin, but it is still a cluster-scoped credential with access across namespaces, including read and write access to workload Secrets. The service-account token is long-lived. Anyone who obtains it can exercise every permission in stackdome-api-server-role; protect stackdome-api-server-account-secret and restrict access to the control-plane namespace.

In Stackdome

With the API server up, the installer finishes the setup through Stackdome’s own API:
  • An admin user named Platform Admin, with the email from --email and the generated password.
  • An organization named Default, with your domain configured on it.
  • A cluster named local — the server itself — registered with the credentials from the RBAC step, so the platform can deploy to it.
  • An in-cluster image registry named default-registry with 50Gi of backing storage, attached to that cluster. It holds the images Stackdome builds from your git repositories.
The in-cluster registry belongs to the cluster and is created with it. It is not one of the entries on the Image registries page — that page is for credentials you add for external registries, and it is empty on a fresh install.

Sign in and confirm the dashboard

Open the dashboard URL from the installer summary. Sign in with the email passed to --email and the generated admin password that you saved from the summary.The Stackdome sign-in form, headed "Welcome back.", with empty Email and Password fields and a Continue buttonChoose Continue →. A successful sign-in opens Stacks, where you can confirm the dashboard is available and the installed organization is ready for applications.The Stacks list, with a "Filter stacks" box above stack cards showing resource and volume counts, an OK status, and when each stack last changed

TLS

What the installer does about certificates depends on the shape of your domain. A domain ending in .nip.io, .sslip.io, .local, or .localhost is classified as a non-TLS domain; any other non-empty domain is classified as a real one.

On a nip.io or other local-style domain

No ClusterIssuer is applied and no Let’s Encrypt certificate is requested. The api-server resource is created with tls: false on its public port and without a cluster-issuer annotation. The chart’s Traefik ingress therefore serves its default self-signed certificate. The final summary still prints an https:// URL for the dashboard. Because the install configured no certificate for that name, treat a browser certificate warning on a trial install as the expected outcome rather than a sign that something went wrong.

On a real domain

The installer applies a ClusterIssuer named letsencrypt-prod, and annotates the api-server resource to use it with tls: true on its public port. The issuer is configured with:
  • ACME server: Let’s Encrypt production, https://acme-v02.api.letsencrypt.org/directory
  • Contact email: the address you passed to --email
  • Account key stored in a Secret named letsencrypt-prod-key
  • An HTTP-01 solver, so validation happens over port 80 on your hostname
The issuer is a cert-manager.io/v1 resource supplied after the stackdome-agent chart is ready. The installer treats a failure to apply it as fatal, so a custom-domain install stops if the cert-manager API is unavailable.
Even once the issuer is applied, the installer does not wait for, or verify, that a certificate was actually issued. If HTTPS on your domain still shows a certificate error after the install finishes, inspect the ClusterIssuer and Certificate resources in the cluster rather than re-running the installer.

Upgrade an existing install

Use the dedicated upgrade command for a version change:
upgrade requires root, a running local k3s service, a usable /etc/rancher/k3s/k3s.yaml, Helm, the stackdome-agent release in stackdome-control-plane, the bootstrap Secret, and the existing api-server resource. It reads the email, domain, database workload type, and secrets from the existing install. If you omit --image, it keeps the deployed API-server image. GitHub flags are also accepted and update the stored credentials; values you omit are reused.

Re-running installation

Re-running with the same flags is handled at every step, and the installer says so as it goes:
Cluster reuse is not matched to this server. On a re-run the installer lists the organization’s clusters and, if the list is not empty, keeps the first entry without checking that it points at this machine. On an organization that already has clusters, a re-run therefore adopts an arbitrary existing one and never registers the local cluster.
Two more consequences are worth knowing before you rely on this:
  • Do not delete stackdome-bootstrap-secrets. Reuse depends on it. If it is gone or incomplete, the installer generates a fresh database password, JWT secret, encryption key, and admin password — against a database and an API server that were set up with the old ones.
  • Changing --domain or --image on a re-run changes the cluster. The api-server resource is re-templated and re-applied with whatever you pass, and a domain that is not already on the organization is added to it. A re-run is not a no-op if the flags differ.