These are the steps I use to set up K3s lightweight kubernetes for local development with Debian Linux. This guide results in a deployment using LetsEncrypt via Caddy for HTTPS support and as a loadbalancer.

Enable IP forwarding.

sudo sysctl -w net.ipv4.ip_forward=1

Install K3s with Traefik disabled.

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable traefik" sh -s -

I then configure a custom container registry in Docker on the same host. This is where I push all of my images.

docker run -d -p 5000:5000 --restart always --name registry registry:2

I deploy images to the registry from other machines by specifying an /etc/docker/daemon.json file in their respective configs like so.

{
    "insecure-registries" : [ "my-server.local:5000" ]
}

To allow K3s to use the Docker image registry I create a config file at /etc/rancher/k3s/registries.yaml like so.

mirrors:
  "registry:5000":
    endpoint:
      - http://127.0.0.1:5000

I restart k3s after that.

systemctl restart k3s

I run a simple Caddy deployment that handles the same behavior I need from Traefik including LetsEncrypt automatic TLS certificate provisioning for HTTPS.

kind: Deployment
apiVersion: apps/v1
metadata:
  name: caddy
  labels:
    name: caddy

spec:
  replicas: 1
  selector:
    matchLabels:
      app: caddy
  template:
    metadata:
      labels:
        app: caddy
    spec:
      containers:
        - name: app
          image: registry:5000/caddy:latest
          ports:
            - containerPort: 80
            - containerPort: 443
          volumeMounts:
            - name: data-files-volume
              mountPath: /data

      volumes:
      - name: data-files-volume
        hostPath:
          path: /mnt/my-apps/caddy
---
apiVersion: v1
kind: Service
metadata:
  name: load-balancer

spec:
  ports:
    - name: http
      port: 80
      targetPort: 80
    - name: https
      port: 443
      targetPort: 443
  type: LoadBalancer
  selector:
    app: caddy

My Caddyfile config looks something like this.

my-site.my-domain.com:443 {
    # This routes traffic to an app running directly on the host.
    reverse_proxy my-host.local.:8000

    tls my-email@willhaley.com
}

my-other-site.my-domain.com:443 {
    # This routes traffic to an app running within k3d.
    reverse_proxy some-app-service.my-namespace.svc.cluster.local.

    tls my-email@willhaley.com
}

After deploying an application I test it in the browser. Certificate propagation can take some time.

Notes