Skip to content

K3s ​

K3s runs the website and application workloads on one server. Traefik receives public HTTPS requests and selects an application by hostname. The workloads share the cluster's DNS, metrics and volume provisioning. The cluster records its own state in embedded SQLite and keeps its administration API outside the public firewall zone. A cluster outage takes down both the web workloads and their public entry point.

The live host configuration supplies a private node address and places local-path data on the host's larger storage filesystem rather than its root filesystem. K3s maintains a canonical kubeconfig whose credentials it can refresh. Treating a copied kubeconfig as an independently maintained credential can leave the copy stale.

Linkwarden and Calagopus maintenance tools work with the installed workloads. The static site has a different release contract. An approved manifest defines its Kubernetes resources, and a normal site release can change only the application image in that template.

Traefik Ingress Controller ​

The packaged Traefik Ingress Controller uses a K3s LoadBalancer Service on TCP 443 only. Public TCP 80 and an HTTP-to-HTTPS redirect are intentionally absent. On the tested single-server ServiceLB path, externalTrafficPolicy: Local preserved the real external client address. That observation is specific to this topology and does not establish trust in arbitrary forwarded headers.

Traefik obtains certificates by proving control of the domain with a DNS record. This ACME DNS-01 challenge lets issuance work with port 80 closed. Production issuance and a local backup of the certificate state were validated. DNS-01 challenge

For darrela.dev, Traefik terminates HTTPS and forwards the request to the site's internal Kubernetes Service. An unprivileged NGINX container serves the files baked into the release image. Linkwarden and the Calagopus Panel have their own routes through the same ingress. A NetworkPolicy limits incoming Pod traffic to the Panel, while Wings remains on the host.

Traefik's access logs also feed CrowdSec, connecting the public request path to detection and native firewall enforcement.

Before this design, Caddy terminated HTTPS on the host outside K3s. It was retired after the Traefik migration was validated, consolidating public HTTPS ingress with the applications running in K3s.

Validating a site release ​

A running web server can serve the previous revision. The release build packages one committed revision and hashes the generated pages and selected assets. A trusted helper on the host verifies the image and selects it in the approved manifest, which K3s applies as an AddOn. This lets the site change its content while authority over routing and security configuration stays on the host. K3s AddOns

After rollout, the helper fetches the expected routes through Traefik over HTTPS, verifies the certificate hostname and compares the response bodies with the build hashes. An unknown route must also return 404. That last check catches a server that answers every path with the homepage.

After the ingress migration, the new pages were visible to an external client while the release checker still probed the retired HTTP listener. It rejected the rollout and then failed to confirm recovery for the same reason. Checking through the active HTTPS listener let the helper verify the previous release and clear the interrupted transaction. On a subsequent release, the checker retried a request after a timeout. Every required response matched its hash and the unknown route returned 404.

Local Path Provisioner and SELinux ​

A persistent volume claim (PVC) gives a workload storage that survives Pod replacement. Here the stock provisioner creates a directory on the host for the volume. A persistent SELinux rule labels the storage tree container_file_t. In the local test, the workload mounted, wrote and read the volume with SELinux enforcing.

Cleanup exercised a different permission boundary. Deleting the claim left the volume in Released and its directory on disk. The cleanup helper ran in a separate Pod whose SELinux categories did not allow it to remove the workload's directory. The local response kept enforcement and the stock provisioner, tracing the failed volume to its helper and directory before any manual cleanup. K3s later recorded successful deletion tests with an upstream fix. K3s issue #14508

Recovery limits ​

Embedded SQLite recovery requires the datastore directory and matching server token together, with the live K3s configuration in the same recovery set. A tested backup stopped K3s, copied that state, restarted the service, and confirmed nodes and pods healthy.

A backup on the same physical storage protects against some configuration mistakes and bad upgrades, not device loss. It also excludes application PVC data and the independent ACME and website-release state. Full host recovery therefore depends on separately protected copies of each state set rather than the K3s datastore alone.

Maintenance explains how to carry these separate state sets through a change and diagnose the result from public ingress inward.

Built with VitePress.