Deploy Anywhere: Hetzner Dedicated Servers

This guide walks through taking a single Hetzner dedicated server, installing k3s, and using Stack to run multiple apps on the same box.

1) Provision the server

  • Create a new dedicated server in the Hetzner Robot or Cloud Console.
  • Choose Ubuntu 22.04 LTS.
  • Add your SSH key and note the public IP.
  • Ensure ports 22, 80, 443, and 6443 are reachable (or use a firewall rule to allow your IP for 6443).

SSH in:

ssh root@YOUR_SERVER_IP

2) Install k3s

curl -sfL https://get.k3s.io | sh -s - --write-kubeconfig-mode 644

Set kubectl access:

export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
kubectl get nodes

You should see the single node in Ready state.

3) Install the Stack CLI

export STACK_VERSION=v1.1.1
curl -OL https://github.com/stack-cli/stack-cli/releases/download/${STACK_VERSION}/stack-linux \
&& chmod +x ./stack-linux \
&& sudo mv ./stack-linux /usr/local/bin/stack

Bootstrap Stack on the k3s cluster:

stack init

4) Install multiple apps

Create one StackApp manifest per namespace. Example: a web frontend and an API service.

frontend.yaml:

apiVersion: stack-cli.dev/v1
kind: StackApp
metadata:
  name: frontend
  namespace: frontend
spec:
  components:
    auth: {}
  services:
    web:
      image: ghcr.io/stack/demo-app:latest
      port: 7903

api.yaml:

apiVersion: stack-cli.dev/v1
kind: StackApp
metadata:
  name: api
  namespace: api
spec:
  components:
    auth: {}
  services:
    web:
      image: ghcr.io/stack/demo-app:latest
      port: 7903

Apply both:

stack deploy --manifest frontend.yaml
stack deploy --manifest api.yaml

Check status:

stack status --manifest frontend.yaml
stack status --manifest api.yaml

Each StackApp gets its own namespace, database, and auth service, all on the same dedicated server.

5) Expose apps to the internet

  • For quick exposure, use the Ingress guide to add a tunnel per StackApp.
  • For production ingress, point your DNS at the server and configure an ingress controller or load balancer.

Next steps