Skip to main content

Documentation Index

Fetch the complete documentation index at: https://ubicloud.com/docs/llms.txt

Use this file to discover all available pages before exploring further.

Windmill is an open-source platform that transforms scripts into UIs, APIs, and workflows. Supporting languages like Python and TypeScript, it simplifies internal tool creation, automation, and scaling for teams. This guide will help you set up Windmill on Ubicloud, with Ubicloud managed Kubernetes and PostgreSQL services.

Preparing the Ubicloud Environment

To prepare the Ubicloud environment for running Windmill, follow the steps outlined in the Ubicloud documentation:

Preparing Your Environment

Step 0: Ensure that your shell environment has kubectl and helm installed.

Use the commands to verify that kubectl and helm are installed:
kubectl version
helm version

Step 1: Obtain the kubeconfig File

  • Download the kubeconfig: Access the Kubernetes cluster in the Ubicloud console and download the kubeconfig file.
  • Copy the file to the default kubeconfig location ($HOME/.kube/config) or set the KUBECONFIG environment variable to configure your Kubernetes client (e.g., kubectl).

Step 2: Create a Namespace for Windmill

Create a namespace for the Windmill deployment:
kubectl create namespace windmill

Step 3: Store the Database Connection String in a Secret

Retrieve the connection string for your PostgreSQL database from the Ubicloud console and create a secret:
kubectl create secret generic -n windmill pg-db-credentials \
--from-literal=url='<postgres connection string copied from Ubicloud console>'

Deploying Windmill

Add Windmill Helm repo:
helm repo add windmill https://windmill-labs.github.io/windmill-helm-charts/
Download the values.yaml file for the Windmill chart:
curl -O https://raw.githubusercontent.com/windmill-labs/windmill-helm-charts/refs/heads/main/charts/windmill/values.yaml
Disable the built-in PostgreSQL database in values.yaml:
postgresql:
  enabled: false
Set the secret name for the database connection string:
windmill:
...
  databaseUrlSecretName: pg-db-credentials
Install the Windmill chart with the modified values.yaml file:
helm -n windmill install my-windmill windmill/windmill -f values.yaml
Wait for all pods to start running:
kubectl -n windmill get pods

Exposing Windmill to the Internet

By default, Windmill chart restricts the windmill-app service to internal cluster access. To access the Windmill UI via a browser, expose the service externally using a load balancer:
kubectl -n windmill patch svc windmill-app -p '{"spec": {"type": "LoadBalancer"}}'
Wait for the service to get an external host assigned:
kubectl -n windmill get service windmill-app

Connecting to Windmill

The application will be accessible via your cluster’s load balancer URL at port 8000 a few minutes after the EXTERNAL-IP is assigned. Run the following command to retrieve the address for your Windmill deployment.
echo "http://$(kubectl -n windmill get service windmill-app --output jsonpath='{.status.loadBalancer.ingress[0].hostname}'):8000"
Congratulations—Windmill is now running on Ubicloud!

Configuring TLS for Secure Access

To expose Windmill securely via HTTPS, we’ll employ Nginx Gateway Fabric, cert-manager, and Let’s Encrypt using the Kubernetes Gateway API.

Installing NGINX Gateway Fabric & cert-manager

Use the following commands to install the Gateway API CRDs, NGINX Gateway Fabric, and cert-manager:
kubectl kustomize https://github.com/nginx/nginx-gateway-fabric/config/crd/gateway-api/standard?ref=v2.5.1 | kubectl apply -f -

helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric \
  --create-namespace -n nginx-gateway

helm repo add jetstack https://charts.jetstack.io
helm repo update

helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager --create-namespace \
  --set crds.enabled=true \
  --set config.apiVersion="controller.config.cert-manager.io/v1alpha1" \
  --set config.kind="ControllerConfiguration" \
  --set config.enableGatewayAPI=true
Next, create a ClusterIssuer to obtain certificates from Let’s Encrypt:
export CLUSTER_ISSUER_EMAIL=email@yourcompany.com

kubectl apply -f <(cat <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
 name: letsencrypt
spec:
 acme:
   server: https://acme-v02.api.letsencrypt.org/directory
   email: $CLUSTER_ISSUER_EMAIL
   privateKeySecretRef:
     name: letsencrypt
   solvers:
   - http01:
       gatewayHTTPRoute: {}
EOF
)

Configuring HTTPS with Gateway API

To expose Windmill securely, you first need the external domain for your cluster. You can find this “Service URL” (e.g., mycluster-services-0b1c1.k8s.ubicloud.com) in the Overview page of your Kubernetes cluster in the Ubicloud console. Alternatively, you can use the address retrieved in the previous step:
kubectl -n windmill get service windmill-app --output jsonpath='{.status.loadBalancer.ingress[0].hostname}'
If you prefer using a custom domain like windmill.yourdomain.com, create a CNAME record with your DNS provider pointing it to the Service URL mentioned above.

Updating Windmill Chart Values

Update the domain values and disable the built-in ingress in values.yaml, as we will manage the Gateway API resources manually:
windmill:
  baseDomain: xxxxx-services-xxxxx.k8s.ubicloud.com # Replace with your Service URL or custom domain
  baseProtocol: https

ingress:
  enabled: false

Reverting Service Type

Since external traffic will now be handled by the Gateway, revert the windmill-app service back to ClusterIP:
kubectl -n windmill patch svc windmill-app -p '{"spec": {"type": "ClusterIP"}}'
Apply the updated values to the Windmill installation:
helm -n windmill upgrade my-windmill windmill/windmill -f values.yaml

Creating Gateway and HTTPRoute

Finally, create the Gateway and HTTPRoute resources to expose Windmill via HTTPS:
export WINDMILL_DOMAIN=xxxxx-services-xxxxx.k8s.ubicloud.com # Replace with your domain

kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: windmill-gateway
  namespace: nginx-gateway
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
        from: All
  - name: https
    hostname: "$WINDMILL_DOMAIN"
    port: 443
    protocol: HTTPS
    allowedRoutes:
      namespaces:
        from: All
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: windmill-tls-cert
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: windmill
  namespace: windmill
spec:
  parentRefs:
  - name: windmill-gateway
    namespace: nginx-gateway
    sectionName: https
  hostnames:
  - "$WINDMILL_DOMAIN"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: windmill-app
      port: 8000
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: windmill-redirect
  namespace: windmill
spec:
  parentRefs:
  - name: windmill-gateway
    namespace: nginx-gateway
    sectionName: http
  hostnames:
  - "$WINDMILL_DOMAIN"
  rules:
  - filters:
    - type: RequestRedirect
      requestRedirect:
        scheme: https
        statusCode: 301
EOF

Verifying the Certificate Status

It may take a few minutes for the certificate to be issued and the gateway to become fully operational. Check the readiness of the TLS certificate for the Windmill application:
kubectl -n nginx-gateway describe cert windmill-tls-cert
Once the certificate is ready, you can access your Windmill application securely at https://xxxxx-services-xxxxx.k8s.ubicloud.com or https://windmill.yourdomain.com.