Skip to main content
The repository holds a complete single-node Kubernetes setup for ARUKZ ERP: an application image (docker/k8s/), Kustomize manifests (infra/k8s/), Terraform that builds one Hetzner Cloud server (infra/terraform/) and a deploy script (deploy-k8s.sh). It has been run end to end on a local k3d cluster: fresh install, a second deploy on the same data, the worker taking queued jobs and the backup job writing a dump. It is not live on any server yet; the hosted service at erp.arukz.com still runs on Docker.

What runs

Try it on your own machine

You need Docker, k3d, kubectl and a Laravel .env for the cluster.
On an empty database the release Job needs ERP_ADMIN_NAME, ERP_ADMIN_EMAIL and ERP_ADMIN_PASSWORD in the .env; a restored dump does not. The app answers only its trusted host names, and the web pods’ health probes send a fixed one (erp.localhost on k3d), so APP_TRUSTED_HOSTS must list it as well as every name the cluster serves.

Build a server on Hetzner

1

Set your host names

infra/k8s/overlays/hetzner/kustomization.yaml names the Ingress host and the host the health probes send; ARUKZ’s values are its own domains. Change both to yours.
2

Fill in the Terraform variables

Copy infra/terraform/terraform.tfvars.example to terraform.tfvars (git-ignored) and set hcloud_token, ssh_public_key and admin_cidrs; optionally location and server_type. Terraform state stays on your machine.
3

Create the server

make tf-plan, then make tf-apply. cloud-init installs k3s on the new server.
4

Bootstrap the cluster

ACME_EMAIL=you@example.in make k8s-bootstrap fetches the kubeconfig and installs cert-manager with a Let’s Encrypt issuer. Point your domain’s DNS at the server’s address first.
5

Deploy

make k8s-hetzner ENV_FILE=path/to/.env. The script refuses to run with uncommitted changes, builds the image, copies it to the server (no registry needed), runs the release Job, rolls the Deployments and smoke-tests the site.
deploy-k8s.sh can be run again safely. kubectl -n arukz-erp rollout undo deploy/web goes back one image; migrations are not undone, so restore a backup if one must be.

Not in this setup

Several nodes, a managed database, autoscaling, an image registry, GitOps and monitoring beyond the app’s own health check are not part of it. The image leaves out Faker, so the sample factory does not load; see Self-hosting with Docker.
Last modified on November 12, 2026