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.4.2" | 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 an issuer in the windmill namespace to obtain certificates from Let’s Encrypt:
kubectl apply -n windmill -f <(cat <<EOF
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-windmill
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: <YOUR E-MAIL ADDREESS>
privateKeySecretRef:
name: letsencrypt
solvers:
- http01:
gatewayHTTPRoute: {}
EOF
)
Setting Up DNS Records for Traffic Routing
Create the Gateway resource. NGINX Gateway Fabric will automatically provision a LoadBalancer service and an NGINX data plane when a Gateway is created.
kubectl apply -n windmill -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: windmill-gateway
spec:
gatewayClassName: nginx
listeners:
- name: http
port: 80
protocol: HTTP
- name: https
port: 443
protocol: HTTPS
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: windmill-tls-cert
EOF
Once the Gateway is created, retrieve the external address of the LoadBalancer Service:
kubectl -n windmill get service windmill-gateway-nginx
You should get a result in the form mycluster-services-0b1c1.k8s.ubicloud.com. We will use this address in the following step to route traffic to the cluster securely.
If you want to use your domain such as windmill.yourdomain.com, create a CNAME record with your DNS provider to route windmill.yourdomain.com to the EXTERNAL-IP associated with the windmill-gateway-nginx service and use that address in the following steps.
Updating Windmill Chart Values and Creating Gateway Resources
First, update the domain values and disable the built-in ingress in values.yaml since we’ll use Gateway API resources directly:
windmill:
baseDomain: xxxxx-services-xxxxx.k8s.ubicloud.com # Replace with your service URL or domain
baseProtocol: https
ingress:
enabled: false
Revert the service type back to ClusterIP since external access will now be handled by the Gateway:
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
Next, update the Gateway to include the hostname for the HTTPS listener, and create the HTTPRoute to expose Windmill:
export WINDMILL_DOMAIN=xxxxx-services-xxxxx.k8s.ubicloud.com # Replace with your service URL or domain
kubectl apply -n windmill -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: windmill-gateway
annotations:
cert-manager.io/issuer: letsencrypt-windmill
spec:
gatewayClassName: nginx
listeners:
- name: http
port: 80
protocol: HTTP
- name: https
hostname: "$WINDMILL_DOMAIN"
port: 443
protocol: HTTPS
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: windmill-tls-cert
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: windmill
spec:
parentRefs:
- name: windmill-gateway
sectionName: https
hostnames:
- "$WINDMILL_DOMAIN"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: windmill-app
port: 8000
EOF
Verifying the Certificate Status
Check the readiness of the TLS certificate for the Windmill application:
kubectl -n windmill 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.