Self-Hosting

TLS and Ingress

Secure your flex.plane deployment with TLS certificates and an ingress controller.

flex.plane runs on Kubernetes and exposes its services through standard Kubernetes ingress. You need an ingress controller and TLS certificates to serve the portal and API securely.

Choose an ingress controller

flex.plane works with any Kubernetes ingress controller. The most common choices:

ControllerNotes
NGINX IngressThe most widely used. Well-tested with flex.plane. Recommended for most deployments.
TraefikPopular in k3s environments. Works well with minimal configuration.
HAProxy IngressGood for high-throughput deployments.

Install your chosen controller following its documentation. For example, with NGINX:

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm install ingress-nginx ingress-nginx/ingress-nginx \
  -n ingress-nginx --create-namespace

The flextenant chart references the ingress class name in its values:

orchestrator:
  ingress:
    enabled: true
    className: "nginx"

portal:
  ingress:
    enabled: true
    className: "nginx"

Configure cert-manager

cert-manager automates TLS certificate provisioning and renewal. It integrates with Let's Encrypt and other ACME providers.

Install cert-manager:

helm repo add jetstack https://charts.jetstack.io
helm install cert-manager jetstack/cert-manager \
  -n cert-manager --create-namespace \
  --set crds.enabled=true

Create a ClusterIssuer for Let's Encrypt:

# cluster-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-account-key
    solvers:
      - http01:
          ingress:
            class: nginx
kubectl apply -f cluster-issuer.yaml

Then reference the issuer in your flex.plane ingress annotations:

orchestrator:
  ingress:
    enabled: true
    tlsEnabled: true
    className: "nginx"
    annotations:
      cert-manager.io/cluster-issuer: "letsencrypt"

portal:
  ingress:
    enabled: true
    tlsEnabled: true
    className: "nginx"
    annotations:
      cert-manager.io/cluster-issuer: "letsencrypt"

cert-manager will automatically request certificates and renew them before expiry.

Use the Let's Encrypt staging server (https://acme-staging-v02.api.letsencrypt.org/directory) for testing to avoid hitting rate limits.

Set up DNS

You need DNS records pointing to your ingress controller's external IP or load balancer. The typical setup uses a single domain with path-based routing:

DNS RecordTargetPurpose
flexplane.example.comIngress controller IPPortal, API, playground
auth.example.comZitadel ingress IPOIDC authentication

If your Zitadel and flex.plane share the same ingress controller, you can use the same IP for both records.

For Kubernetes clusters running on bare metal or on-premises, you may need to configure a LoadBalancer service type with MetalLB or similar, or use NodePort with an external reverse proxy.

The OIDC issuer URL must be accessible from both the browser (for login redirects) and the orchestrator (for token validation). If these are on different networks, ensure the DNS resolves correctly from both locations.

WebSocket support

The orchestrator's terminal proxy (port 7777) uses WebSocket connections for VM console access. Make sure your ingress controller is configured to support WebSocket upgrades. For NGINX Ingress, this typically works out of the box. If you use a CDN or external load balancer in front of your ingress, verify that it passes WebSocket connections through.