<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Mendix]]></title><description><![CDATA[Mendix]]></description><link>https://mendix.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1593680282896/kNC7E8IR4.png</url><title>Mendix</title><link>https://mendix.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 18 Sep 2026 20:40:21 GMT</lastBuildDate><atom:link href="https://mendix.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Deploy Mendix on a Local Floci Kubernetes Lab]]></title><description><![CDATA[A verified Windows guide for Floci K3s PostgreSQL S3 ingress nginx GitHub Container Registry and ngrok



Guide detail
Value



Prepared for
Sukhvinder Singh


Verified on
13 September 2026


Host
Win]]></description><link>https://mendix.hashnode.dev/deploy-mendix-on-a-local-floci-kubernetes-lab</link><guid isPermaLink="true">https://mendix.hashnode.dev/deploy-mendix-on-a-local-floci-kubernetes-lab</guid><category><![CDATA[Devops articles]]></category><category><![CDATA[mendix]]></category><category><![CDATA[mendixdevelopment]]></category><dc:creator><![CDATA[Sukhvindra]]></dc:creator><pubDate>Sun, 13 Sep 2026 13:11:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a8ae4187b86f704781b0d3d/8b220867-ac90-4892-a71d-3c8558585d39.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A verified Windows guide for Floci K3s PostgreSQL S3 ingress nginx GitHub Container Registry and ngrok</p>
<table>
<thead>
<tr>
<th><strong>Guide detail</strong></th>
<th><strong>Value</strong></th>
</tr>
</thead>
<tbody><tr>
<td>Prepared for</td>
<td>Sukhvinder Singh</td>
</tr>
<tr>
<td>Verified on</td>
<td>13 September 2026</td>
</tr>
<tr>
<td>Host</td>
<td>Windows 11 with Docker Desktop and WSL2</td>
</tr>
<tr>
<td>Outcome</td>
<td>Mendix 11.13.0 runtime accessible through a stable public ngrok URL</td>
</tr>
<tr>
<td>Recovery</td>
<td>One PowerShell script restores the lab after Windows sign in</td>
</tr>
</tbody></table>
<p>This guide rebuilds the lab from an empty Floci environment to a running Mendix application. It incorporates the corrections verified during the deployment: fixed Docker addresses, Kubernetes EndpointSlices, GitHub Container Registry authentication, a free ngrok Cloud Endpoint, and a restart automation that returned exit code 0.</p>
<p><strong>Scope:</strong> This is a learning and demonstration environment. Floci emulates AWS services locally; it does not reproduce production AWS security, resilience, backups, networking, or service-level guarantees.</p>
<h1>Successful final state</h1>
<table>
<thead>
<tr>
<th><strong>Component</strong></th>
<th><strong>Verified state</strong></th>
</tr>
</thead>
<tbody><tr>
<td>Floci</td>
<td>Healthy at 172.20.0.6:4566 with persistent storage</td>
</tr>
<tr>
<td>Kubernetes</td>
<td>Floci EKS-compatible K3s node Ready; context floci-mendix</td>
</tr>
<tr>
<td>PostgreSQL</td>
<td>Floci RDS container at 172.20.0.3:5432</td>
</tr>
<tr>
<td>S3</td>
<td>Bucket mendix-floci-files through floci-s3 service</td>
</tr>
<tr>
<td>Ingress</td>
<td>ingress-nginx; NodePorts 30080 and 30443</td>
</tr>
<tr>
<td>Registry</td>
<td>Private GHCR repository with Kubernetes pull secret</td>
</tr>
<tr>
<td>Mendix app</td>
<td>Build and runtime green; 1 of 1 replicas running</td>
</tr>
<tr>
<td>Public URL</td>
<td><a href="https://completable-noncommemorational-terica.ngrok-free.dev/">https://completable-noncommemorational-terica.ngrok-free.dev/</a></td>
</tr>
<tr>
<td>Restart task</td>
<td>Start Floci Mendix Lab; LastTaskResult 0</td>
</tr>
</tbody></table>
<h1>Contents</h1>
<blockquote>
<p><strong>1.</strong> Architecture and fixed addressing</p>
<p><strong>2.</strong> Prerequisites and security rules</p>
<p><strong>3.</strong> Create the persistent Floci foundation</p>
<p><strong>4.</strong> Create and connect the K3s cluster</p>
<p><strong>5.</strong> Configure PostgreSQL and S3</p>
<p><strong>6.</strong> Register the namespace and install the Mendix components</p>
<p><strong>7.</strong> Install ingress nginx and connect ngrok</p>
<p><strong>8.</strong> Configure database storage ingress and registry plans</p>
<p><strong>9.</strong> Create a package and a development environment</p>
<p><strong>10.</strong> Fix the free ngrok hostname</p>
<p><strong>11.</strong> Troubleshoot GHCR image pulls</p>
<p><strong>12.</strong> Restore the lab automatically after restart</p>
<p><strong>13.</strong> Final validation and operating notes</p>
</blockquote>
<h1>Architecture and fixed addressing</h1>
<p>The public ngrok Cloud Endpoint forwards traffic to the local ngrok agent at default.internal. The agent sends traffic to localhost port 8080, where kubectl forwards it to ingress-nginx. Kubernetes routes the request to the Mendix runtime. The runtime reaches PostgreSQL and S3 through stable Kubernetes services backed by external EndpointSlices.</p>
<blockquote>
<p>Internet HTTPS<br />-&gt; ngrok Cloud Endpoint<br />-&gt; ngrok agent default.internal<br />-&gt; localhost:8080<br />-&gt; ingress-nginx service port 80<br />-&gt; Mendix Ingress and runtime<br />-&gt; floci-rds:5432 and floci-s3:4566</p>
</blockquote>
<table>
<thead>
<tr>
<th><strong>Address</strong></th>
<th><strong>Purpose</strong></th>
</tr>
</thead>
<tbody><tr>
<td>172.20.0.1</td>
<td>floci_default network gateway</td>
</tr>
<tr>
<td>172.20.0.3</td>
<td>Floci PostgreSQL container</td>
</tr>
<tr>
<td>172.20.0.4</td>
<td>Floci K3s cluster container</td>
</tr>
<tr>
<td>172.20.0.6</td>
<td>Floci API and S3 emulator</td>
</tr>
<tr>
<td>localhost:6500</td>
<td>K3s Kubernetes API endpoint</td>
</tr>
<tr>
<td>localhost:8080</td>
<td>Local ingress port-forward</td>
</tr>
<tr>
<td>localhost:4566</td>
<td>Floci API from Windows</td>
</tr>
</tbody></table>
<h1>Prerequisites and security rules</h1>
<ul>
<li><p>Docker Desktop with WSL2 enabled.</p>
</li>
<li><p>AWS CLI, kubectl, Helm 3, mxpc-cli, and ngrok v3 available on Windows.</p>
</li>
<li><p>A GitHub account and a private GHCR package path.</p>
</li>
<li><p>A reserved ngrok free domain and an authenticated ngrok agent.</p>
</li>
<li><p>Do not publish Namespace Secrets, GitHub tokens, ngrok authtokens, database passwords, subscription secrets, signed package URLs, or generated YAML containing credentials.</p>
</li>
<li><p>Never run docker system prune --volumes or docker volume prune against this lab.</p>
</li>
</ul>
<h1>Create the persistent Floci foundation</h1>
<h2>Create the external Docker network</h2>
<p>The Compose file uses an external network. A first-time reader must create it before running docker compose.</p>
<blockquote>
<p>docker network create `<br />--driver bridge `<br />--subnet 172.20.0.0/16 `<br />--gateway 172.20.0.1 `<br />floci_default</p>
</blockquote>
<p>Verify the network configuration:</p>
<blockquote>
<p>docker network inspect floci_default</p>
</blockquote>
<h2>Create persistent storage</h2>
<blockquote>
<p>New-Item -ItemType Directory -Force -Path "D:\Floci\data"</p>
</blockquote>
<h2>Create the Compose file</h2>
<p>Save this as D:\Developer-Knowledge-Hub\01-Inbox\Floci\compose.yml. The fixed address prevents the S3 endpoint from changing after a restart.</p>
<blockquote>
<p>services:<br />floci:<br />image: floci/floci:latest<br />ports:</p>
<ul>
<li><p>"4566:4566"<br />environment:<br />FLOCI_STORAGE_MODE: persistent<br />FLOCI_STORAGE_PERSISTENT_PATH: /app/data<br />volumes:</p>
</li>
<li><p>D:/Floci/data:/app/data</p>
</li>
<li><p>/var/run/docker.sock:/var/run/docker.sock<br />networks:<br />default:<br />ipv4_address: 172.20.0.6</p>
</li>
</ul>
<p>networks:<br />default:<br />external: true<br />name: floci_default</p>
<p>docker compose -f "D:\Developer-Knowledge-Hub\01-Inbox\Floci\compose.yml" up -d<br />docker inspect floci-floci-1 --format "Status={{.State.Status}} Health={{.State.Health.Status}}"</p>
</blockquote>
<p>Expected result: Status=running and Health=healthy.</p>
<h2>Verify Floci services</h2>
<blockquote>
<p>Invoke-RestMethod "<a href="http://localhost:4566/%5C_localstack/health">http://localhost:4566/\_localstack/health</a>" | ConvertTo-Json -Depth 10</p>
</blockquote>
<h1>Create and connect the K3s cluster</h1>
<h2>Create the emulated IAM role</h2>
<blockquote>
<p>$trustPolicy = '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"eks.amazonaws.com"},"Action":"sts:AssumeRole"}]}'</p>
<p>aws iam create-role `<br />--role-name FlociEksClusterRole `<br />--assume-role-policy-document $trustPolicy `<br />--endpoint-url <a href="http://localhost:4566">http://localhost:4566</a> `<br />--region us-east-1 `<br />--no-cli-pager</p>
</blockquote>
<h2>Create the EKS-compatible cluster</h2>
<blockquote>
<p>aws eks create-cluster `<br />--name mendix-floci-cluster `<br />--role-arn arn:aws:iam::000000000000:role/FlociEksClusterRole `<br />--resources-vpc-config "subnetIds=subnet-default-a,subnet-default-b,subnet-default-c,securityGroupIds=sg-default,endpointPublicAccess=true,endpointPrivateAccess=false" `<br />--endpoint-url <a href="http://localhost:4566">http://localhost:4566</a> `<br />--region us-east-1 `<br />--no-cli-pager</p>
<p>aws eks describe-cluster `<br />--name mendix-floci-cluster `<br />--endpoint-url <a href="http://localhost:4566">http://localhost:4566</a> `<br />--region us-east-1 `<br />--query "cluster.{Status:status,Endpoint:endpoint}" `<br />--no-cli-pager</p>
</blockquote>
<p>Continue when the status is ACTIVE and the endpoint is <a href="https://localhost:6500">https://localhost:6500</a>.</p>
<h2>Attach the K3s container to the fixed network</h2>
<blockquote>
<p>docker network connect `<br />--ip 172.20.0.4 `<br />floci_default `<br />floci-eks-mendix-floci-cluster</p>
</blockquote>
<p>If Docker reports that the endpoint already exists, inspect the existing address instead of reconnecting it.</p>
<h2>Create the kubeconfig context</h2>
<blockquote>
<p>aws eks update-kubeconfig `<br />--name mendix-floci-cluster `<br />--alias floci-mendix `<br />--endpoint-url <a href="http://localhost:4566">http://localhost:4566</a> `<br />--region us-east-1</p>
<p>kubectl config use-context floci-mendix<br />kubectl get nodes -o wide<br />kubectl get storageclass</p>
</blockquote>
<p>Expected result: one K3s control-plane node is Ready and local-path is the default StorageClass.</p>
<h1>Configure PostgreSQL and S3</h1>
<h2>Create PostgreSQL</h2>
<blockquote>
<p>aws rds create-db-subnet-group `<br />--db-subnet-group-name mendix-rds-subnet-group `<br />--db-subnet-group-description "Subnet group for Mendix PostgreSQL" `<br />--subnet-ids subnet-default-a subnet-default-b subnet-default-c `<br />--endpoint-url <a href="http://localhost:4566">http://localhost:4566</a> `<br />--region us-east-1 `<br />--no-cli-pager</p>
</blockquote>
<p>Prompt securely for the database password so it is not stored in PowerShell history:</p>
<blockquote>
<p>$dbSecurePassword = Read-Host "Enter the PostgreSQL password" -AsSecureString<br />$dbPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto(<br />[Runtime.InteropServices.Marshal]::SecureStringToBSTR($dbSecurePassword)<br />)</p>
<p>aws rds create-db-instance `<br />--db-instance-identifier mendix-postgres `<br />--db-instance-class db.t3.micro `<br />--engine postgres `<br />--allocated-storage 20 `<br />--master-username mendixadmin `<br />--master-user-password $dbPassword `<br />--db-name mendixdb `<br />--db-subnet-group-name mendix-rds-subnet-group `<br />--vpc-security-group-ids sg-default `<br />--no-publicly-accessible `<br />--endpoint-url <a href="http://localhost:4566">http://localhost:4566</a> `<br />--region us-east-1 `<br />--no-cli-pager</p>
<p>\(dbPassword = \)null<br />\(dbSecurePassword = \)null</p>
</blockquote>
<p>Important: Floci API metadata may advertise 172.20.0.6:7001, but Kubernetes must connect to the actual PostgreSQL container on port 5432. Inspect the generated container and attach it to the fixed network.</p>
<blockquote>
<p>$RdsContainer = docker ps -a --format "{{.Names}}" |<br />Where-Object { $_ -like "floci-rds-*" } |<br />Select-Object -First 1</p>
<p>docker network connect --ip 172.20.0.3 floci_default $RdsContainer</p>
</blockquote>
<h2>Create the PostgreSQL Kubernetes service</h2>
<blockquote>
<p>kubectl create namespace mendix-floci<br />kubectl create service clusterip floci-rds --tcp=5432:5432 -n mendix-floci<br />kubectl patch service floci-rds -n mendix-floci --type=merge --patch '{\spec\:{\selector\:null}}'</p>
<p>@"<br />apiVersion: discovery.k8s.io/v1<br />kind: EndpointSlice<br />metadata:<br />name: floci-rds-external<br />namespace: mendix-floci<br />labels:<br />kubernetes.io/service-name: floci-rds<br />addressType: IPv4<br />ports:</p>
<ul>
<li><p>name: 5432-5432<br />protocol: TCP<br />port: 5432<br />endpoints:</p>
</li>
<li><p>addresses: ["172.20.0.3"]<br />conditions:<br />ready: true<br />"@ | kubectl apply -f -</p>
</li>
</ul>
</blockquote>
<p>The EndpointSlice port name must exactly match the generated Service port name 5432-5432. A different name can cause the Service DNS test to fail even when the direct IP succeeds.</p>
<blockquote>
<p>kubectl run rds-service-test -n mendix-floci `<br />--image=busybox:1.36 --restart=Never --rm -i `<br />--command -- nc -zvw5 floci-rds.mendix-floci.svc.cluster.local 5432</p>
</blockquote>
<h2>Create S3 storage</h2>
<blockquote>
<p>aws s3api create-bucket `<br />--bucket mendix-floci-files `<br />--endpoint-url <a href="http://localhost:4566">http://localhost:4566</a> `<br />--region us-east-1 `<br />--no-cli-pager</p>
<p>kubectl create service clusterip floci-s3 --tcp=4566:4566 -n mendix-floci<br />kubectl patch service floci-s3 -n mendix-floci --type=merge --patch '{\spec\:{\selector\:null}}'</p>
<p>@"<br />apiVersion: discovery.k8s.io/v1<br />kind: EndpointSlice<br />metadata:<br />name: floci-s3-external<br />namespace: mendix-floci<br />labels:<br />kubernetes.io/service-name: floci-s3<br />addressType: IPv4<br />ports:</p>
<ul>
<li><p>name: 4566-4566<br />protocol: TCP<br />port: 4566<br />endpoints:</p>
</li>
<li><p>addresses: ["172.20.0.6"]<br />conditions:<br />ready: true<br />"@ | kubectl apply -f -</p>
</li>
</ul>
</blockquote>
<h1>Register the namespace and install Mendix</h1>
<p>Keep the existing Portal cluster registration if it represents this lab. Create or reuse the Kubernetes namespace mendix-floci, then add that namespace in Mendix on Kubernetes Cluster Manager. Use the cluster type Kubernetes because the actual node is K3s.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a8ae4187b86f704781b0d3d/a052558c-fc5e-4155-989a-43482ef850ea.png" alt="" style="display:block;margin:0 auto" />

<img src="media/image1.png" alt="" style="display:block;margin:0 auto" />

<p><em>Mendix namespace installation page. Namespace identifiers and secrets must remain redacted.</em></p>
<h2>Run the namespace installer</h2>
<blockquote>
<p>.\mxpc-cli.exe installer -n mendix-floci -i &lt;NAMESPACE_ID&gt; -s &lt;NAMESPACE_SECRET&gt;</p>
</blockquote>
<p>In the installer, complete Base Installation. Verify that the Agent and Operator become healthy.</p>
<blockquote>
<p>kubectl get pods -n mendix-floci -o wide</p>
</blockquote>
<img src="https://cdn.hashnode.com/uploads/covers/6a8ae4187b86f704781b0d3d/523f2cc2-56ec-4d8f-9f2f-2be7918ead52.png" alt="" style="display:block;margin:0 auto" />

<img src="media/image2.png" alt="" style="display:block;margin:0 auto" />

<p><em>The namespace is connected after the Mendix Agent and Operator are running.</em></p>
<h1>Install ingress nginx and connect ngrok</h1>
<h2>Install ingress nginx</h2>
<blockquote>
<p>helm repo add ingress-nginx <a href="https://kubernetes.github.io/ingress-nginx">https://kubernetes.github.io/ingress-nginx</a><br />helm repo update</p>
<p>helm install ingress-nginx ingress-nginx/ingress-nginx `<br />--namespace ingress-nginx `<br />--create-namespace `<br />--set controller.service.type=NodePort `<br />--set controller.service.nodePorts.http=30080 `<br />--set controller.service.nodePorts.https=30443 `<br />--set controller.ingressClassResource.default=true</p>
<p>kubectl get pods -n ingress-nginx -o wide<br />kubectl get ingressclass</p>
</blockquote>
<p>Expected result: ingress-nginx-controller is 1/1 Running and the nginx IngressClass exists.</p>
<h2>Reserve and connect the ngrok domain</h2>
<p>Reserve the free domain completable-noncommemorational-terica.ngrok-free.dev in ngrok. Configure the Cloud Endpoint to forward to <a href="https://default.internal">https://default.internal</a>. The public ngrok endpoint terminates TLS; Kubernetes ingress TLS remains disabled in this lab.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a8ae4187b86f704781b0d3d/555a1cf2-b30a-447e-a191-8615cbc90b51.png" alt="" style="display:block;margin:0 auto" />

<img src="media/image3.png" alt="" style="display:block;margin:0 auto" />

<p><em>Reserved ngrok public Cloud Endpoint.</em></p>
<p>Start a local port-forward and keep the process running:</p>
<blockquote>
<p>kubectl port-forward -n ingress-nginx service/ingress-nginx-controller 8080:80</p>
</blockquote>
<p>In a second PowerShell window, start the ngrok agent from its installation directory:</p>
<blockquote>
<p>.\ngrok.exe http 8080 --url <a href="https://default.internal">https://default.internal</a></p>
</blockquote>
<p>If ERR_NGROK_334 appears, an older ngrok process already owns the endpoint. Inspect and stop only that stale process, then run the correct command again.</p>
<blockquote>
<p>Get-CimInstance Win32_Process |<br />Where-Object { $_.Name -eq "ngrok.exe" } |<br />Select-Object ProcessId, CommandLine</p>
</blockquote>
<h1>Configure Mendix plans and registry</h1>
<h2>Database plan</h2>
<table>
<thead>
<tr>
<th><strong>Field</strong></th>
<th><strong>Value</strong></th>
</tr>
</thead>
<tbody><tr>
<td>Name</td>
<td>floci-rds-postgres</td>
</tr>
<tr>
<td>Host</td>
<td>floci-rds.mendix-floci.svc.cluster.local</td>
</tr>
<tr>
<td>Port</td>
<td>5432</td>
</tr>
<tr>
<td>Strict TLS</td>
<td>Off for the local emulator</td>
</tr>
<tr>
<td>Database Name</td>
<td>postgres</td>
</tr>
<tr>
<td>Authentication</td>
<td>static</td>
</tr>
<tr>
<td>Username</td>
<td>mendixadmin</td>
</tr>
<tr>
<td>Password</td>
<td>The securely created RDS administrator password</td>
</tr>
</tbody></table>
<img src="media/image4.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6a8ae4187b86f704781b0d3d/8f00f8c9-bb42-4e58-a470-df8330637aee.png" alt="" style="display:block;margin:0 auto" />

<p><em>The PostgreSQL database plan validates successfully with the configured master username.</em></p>
<h2>S3 storage plan</h2>
<table>
<thead>
<tr>
<th><strong>Field</strong></th>
<th><strong>Value</strong></th>
</tr>
</thead>
<tbody><tr>
<td>Name</td>
<td>floci-s3-storage</td>
</tr>
<tr>
<td>Type</td>
<td>amazon-s3</td>
</tr>
<tr>
<td>Endpoint</td>
<td><a href="http://floci-s3.mendix-floci.svc.cluster.local:4566">http://floci-s3.mendix-floci.svc.cluster.local:4566</a></td>
</tr>
<tr>
<td>Bucket Prefix</td>
<td>mendix-floci-files</td>
</tr>
<tr>
<td>IRSA</td>
<td>Off</td>
</tr>
<tr>
<td>Share bucket</td>
<td>Off</td>
</tr>
<tr>
<td>Credentials</td>
<td>Local emulator credentials only; mask them in screenshots</td>
</tr>
</tbody></table>
<img src="media/image5.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6a8ae4187b86f704781b0d3d/77583f81-344f-4d1c-9d76-90e8450f2924.png" alt="" style="display:block;margin:0 auto" />

<p><em>The Floci S3 storage plan validates through the Kubernetes service.</em></p>
<h2>Ingress configuration</h2>
<table>
<thead>
<tr>
<th><strong>Field</strong></th>
<th><strong>Value</strong></th>
</tr>
</thead>
<tbody><tr>
<td>Ingress Type</td>
<td>kubernetes-ingress</td>
</tr>
<tr>
<td>Domain Name</td>
<td>completable-noncommemorational-terica.ngrok-free.dev</td>
</tr>
<tr>
<td>Path</td>
<td>/</td>
</tr>
<tr>
<td>Enable TLS</td>
<td>Off; ngrok provides public HTTPS</td>
</tr>
<tr>
<td>Custom Ingress Class</td>
<td>On</td>
</tr>
<tr>
<td>Ingress Class Name</td>
<td>nginx</td>
</tr>
<tr>
<td>Set class as annotation</td>
<td>Off</td>
</tr>
</tbody></table>
<img src="media/image6.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6a8ae4187b86f704781b0d3d/9d35568a-5f79-48ed-9122-7e7cb935616c.png" alt="" style="display:block;margin:0 auto" />

<p><em>Ingress uses the reserved ngrok hostname and nginx class.</em></p>
<h2>GitHub Container Registry</h2>
<p>Create a GitHub personal access token with read:packages and write:packages. Never put the token directly in a published command or screenshot.</p>
<table>
<thead>
<tr>
<th><strong>Field</strong></th>
<th><strong>Value</strong></th>
</tr>
</thead>
<tbody><tr>
<td>Registry Type</td>
<td>generic</td>
</tr>
<tr>
<td>Pull URL</td>
<td>ghcr.io</td>
</tr>
<tr>
<td>Push URL</td>
<td>ghcr.io</td>
</tr>
<tr>
<td>Registry Name</td>
<td>sukhvindra-singh/mendix-resources</td>
</tr>
<tr>
<td>Authentication</td>
<td>On</td>
</tr>
<tr>
<td>User</td>
<td>sukhvindra-singh</td>
</tr>
<tr>
<td>Password</td>
<td>GitHub token; masked</td>
</tr>
<tr>
<td>Default service account</td>
<td>Add credentials to pull secrets</td>
</tr>
</tbody></table>
<p>Use only owner/repository in Registry Name. Do not enter a tag template in that field; Mendix creates the environment-specific tag.</p>
<img src="media/image7.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6a8ae4187b86f704781b0d3d/c80fe079-6fd0-4474-8d84-a2fe97515203.png" alt="" style="display:block;margin:0 auto" />

<p><em>Corrected GHCR configuration. The token remains masked.</em></p>
<h2>Evaluate and apply the configuration</h2>
<p>Evaluate Configuration should report Valid configuration for Storage Plan, Database Plan, Ingress, and Registry. Then select Write YAML and Apply Configuration. Treat the generated YAML as sensitive because it can contain credentials.</p>
<img src="media/image8.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6a8ae4187b86f704781b0d3d/c5bac207-6663-47ad-8818-febd61becc15.png" alt="" style="display:block;margin:0 auto" />

<p><em>All four namespace resources pass configuration evaluation.</em></p>
<img src="media/image9.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6a8ae4187b86f704781b0d3d/bc617c2c-62ed-4ec4-9c00-2eb218508ee4.png" alt="" style="display:block;margin:0 auto" />

<p><em>The installer successfully applies all namespace configuration.</em></p>
<h1>Create a package and development environment</h1>
<h2>Build a deployment package</h2>
<blockquote>
<p><strong>1.</strong> Open the app in Mendix Portal and go to Deployment, Environments, Deployment Packages.</p>
<p><strong>2.</strong> Select Create Deployment Package.</p>
<p><strong>3.</strong> Choose the main branch and the required revision.</p>
<p><strong>4.</strong> Enter the semantic version and select Build this revision.</p>
<p><strong>5.</strong> Wait for the package to show a green completed indicator.</p>
</blockquote>
<img src="media/image10.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6a8ae4187b86f704781b0d3d/6d085eb8-e26f-4d7c-95d7-f08d7b3eaaef.png" alt="" style="display:block;margin:0 auto" />

<p><em>Select the main branch for the deployment package.</em></p>
<img src="media/image11.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6a8ae4187b86f704781b0d3d/8198cd63-faef-4394-93cf-46526599d2f5.png" alt="" style="display:block;margin:0 auto" />

<p><em>Select the required main-branch revision.</em></p>
<img src="media/image12.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6a8ae4187b86f704781b0d3d/38ca3207-4868-466f-8a95-eed2343737d8.png" alt="" style="display:block;margin:0 auto" />

<p><em>Review the version and build the selected revision.</em></p>
<h2>Create the Development environment</h2>
<blockquote>
<p><strong>1.</strong> Select Create Environment and choose the newly completed package.</p>
<p><strong>2.</strong> Keep the generated lowercase environment ID. The verified ID was a0y77t7f.</p>
<p><strong>3.</strong> Set Environment Name and Purpose to Development.</p>
<p><strong>4.</strong> Select namespace mendix-floci on floci-mendix-cluster.</p>
<p><strong>5.</strong> Use the genuine Mendix subscription secret only when a licensed runtime is available. Never use a GitHub token in this field.</p>
<p><strong>6.</strong> Choose XS resources, floci-rds-postgres, and floci-s3-storage.</p>
<p><strong>7.</strong> Create the environment and wait for Build and Runtime to become green.</p>
</blockquote>
<img src="media/image13.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6a8ae4187b86f704781b0d3d/9e69ac6f-9d11-4bbb-8d2e-c9049ac0fd17.png" alt="" style="display:block;margin:0 auto" />

<p><em>Development environment identity and namespace selection. The subscription secret is masked.</em></p>
<img src="media/image14.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6a8ae4187b86f704781b0d3d/d9dfbb63-e261-4ff2-b057-14292fd6ec75.png" alt="" style="display:block;margin:0 auto" />

<p><em>XS runtime resources with the verified database and storage plans.</em></p>
<h1>Fix the free ngrok hostname</h1>
<p>Mendix normally prefixes the namespace domain with the environment ID. A free ngrok reserved domain covers the exact hostname, not an arbitrary environment subdomain. Set spec.appURL to the hostname only. Do not include http://, https://, or a trailing slash; Kubernetes rejects a scheme as an invalid Ingress host.</p>
<p>Use the generated environment ID shown by MendixApp:</p>
<blockquote>
<p>kubectl get mendixapp -n mendix-floci</p>
</blockquote>
<p>Apply the hostname-only override:</p>
<blockquote>
<p>kubectl patch mendixapp a0y77t7f `<br />-n mendix-floci `<br />--type=merge `<br />--patch '{\spec\:{\appURL\:\completable-noncommemorational-terica.ngrok-free.dev\}}'</p>
</blockquote>
<p>The Operator should reconcile the Ingress and status. If it repeatedly restores the environment prefix, use the controlled sequence below.</p>
<blockquote>
<p>kubectl scale deployment mendix-operator -n mendix-floci --replicas=0</p>
<p>kubectl patch ingress a0y77t7f -n mendix-floci --type=json `<br />--patch '[{\op\:\replace\,\path\:\/spec/rules/0/host\,\value\:\completable-noncommemorational-terica.ngrok-free.dev\}]'</p>
<p>kubectl patch mendixapp a0y77t7f -n mendix-floci --subresource=status `<br />--type=merge `<br />--patch '{\status\:{\appURL\:\<a href="http://completable-noncommemorational-terica.ngrok-free.dev/%5C%5C%7D%7D">http://completable-noncommemorational-terica.ngrok-free.dev/\\}}</a>'</p>
<p>kubectl patch mendixapp a0y77t7f -n mendix-floci --type=merge `<br />--patch '{\spec\:{\appURL\:\completable-noncommemorational-terica.ngrok-free.dev\}}'</p>
<p>kubectl scale deployment mendix-operator -n mendix-floci --replicas=1</p>
</blockquote>
<p>Wait for the Operator to become ready, refresh Mendix Portal, and confirm the Network, Storage, Database, Service Account, Build, and Runtime indicators are green.</p>
<blockquote>
<p>Invoke-WebRequest `<br />-Uri "<a href="https://completable-noncommemorational-terica.ngrok-free.dev/">https://completable-noncommemorational-terica.ngrok-free.dev/</a>" `<br />-UseBasicParsing</p>
</blockquote>
<p>Expected result: StatusCode 200 and StatusDescription OK.</p>
<img src="media/image15.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6a8ae4187b86f704781b0d3d/a0b0843c-9d32-4b7b-a64b-2fdb961442ef.png" alt="" style="display:block;margin:0 auto" />

<p><em>Verified final environment: infrastructure, build, and runtime checks are green and the fixed URL is displayed.</em></p>
<p>The optional Licensed Runtime counter can remain 0 of 1 when no commercial runtime subscription is activated. It does not invalidate this local demonstration when the runtime is healthy and the application returns HTTP 200.</p>
<h1>Troubleshoot GHCR image pulls</h1>
<h2>Symptom</h2>
<p>The runtime pod reports ErrImagePull or ImagePullBackOff. Pod events contain failed to authorize and 401 Unauthorized for ghcr.io. If imagePullSecrets is empty, Kubernetes attempted an anonymous pull from a private package.</p>
<h2>Diagnosis</h2>
<blockquote>
<p>kubectl describe pod &lt;RUNTIME_POD&gt; -n mendix-floci<br />kubectl get pod &lt;RUNTIME_POD&gt; -n mendix-floci -o jsonpath="{.spec.imagePullSecrets}"<br />kubectl get secrets -n mendix-floci<br />kubectl get pod &lt;RUNTIME_POD&gt; -n mendix-floci -o jsonpath="{.spec.serviceAccountName}"</p>
</blockquote>
<p>Expected secret: mendix-registry-generic-secret. The verified runtime used the default service account.</p>
<h2>Attach the pull secret</h2>
<p>This Windows-compatible command preserves the JSON quotes passed to kubectl:</p>
<blockquote>
<p>kubectl patch serviceaccount default -n mendix-floci --type=merge `<br />--patch '{\imagePullSecrets\:[{\name\:\mendix-registry-generic-secret\}]}'</p>
</blockquote>
<p>Delete only the failed runtime pod. Its Deployment recreates it with the pull secret.</p>
<blockquote>
<p>kubectl delete pod &lt;RUNTIME_POD&gt; -n mendix-floci</p>
</blockquote>
<p>Expected progression: ErrImagePull, ContainerCreating, then 2/2 Running. Temporary readiness HTTP 500 responses can occur while the Mendix runtime initializes.</p>
<h2>Rotate the GHCR credential securely</h2>
<blockquote>
<p>$ghcrSecureToken = Read-Host "Enter the new GitHub token" -AsSecureString<br />$ghcrToken = [Runtime.InteropServices.Marshal]::PtrToStringAuto(<br />[Runtime.InteropServices.Marshal]::SecureStringToBSTR($ghcrSecureToken)<br />)</p>
<p>kubectl create secret docker-registry mendix-registry-generic-secret `<br />-n mendix-floci `<br />--docker-server=ghcr.io `<br />--docker-username=sukhvindra-singh `<br />--docker-password="$ghcrToken" `<br />--dry-run=client -o yaml | kubectl apply -f -</p>
<p>\(ghcrToken = \)null<br />\(ghcrSecureToken = \)null</p>
</blockquote>
<h1>Restore the lab automatically after restart</h1>
<p>Docker containers and Kubernetes volumes persist, but ngrok and kubectl port-forward are host processes and do not reliably resume after Windows restarts. The verified startup script checks Docker Desktop, recreates the fixed network when absent, starts Floci/K3s/RDS, repairs fixed addresses, waits for Kubernetes and ingress, starts forwarding processes, and validates the public URL.</p>
<h2>Create the script</h2>
<p>Save the following as D:\Floci\scripts\Start-FlociLab.ps1. Adjust only ComposeFile or NgrokExe if the local paths differ.</p>
<blockquote>
<p>$ErrorActionPreference = "Stop"</p>
<p>$ComposeFile = "D:\Developer-Knowledge-Hub\01-Inbox\Floci\compose.yml"<br />$NgrokExe = "C:\Users\sukhv\Downloads\ngrok-v3-stable-windows-amd64\ngrok.exe"<br />$DockerNetwork = "floci_default"<br />$K3sContainer = "floci-eks-mendix-floci-cluster"<br />$KubeContext = "floci-mendix"<br />$Namespace = "mendix-floci"<br />$PublicDomain = "completable-noncommemorational-terica.ngrok-free.dev"<br />\(PublicURL = "https://\)PublicDomain/"<br />$LogDirectory = "D:\Floci\scripts\logs"<br />New-Item -ItemType Directory -Force -Path $LogDirectory | Out-Null</p>
<p>function Test-Docker {<br />docker info *&gt; $null<br />return ($LASTEXITCODE -eq 0)<br />}</p>
<p>function Start-ContainerIfStopped([string]$Name) {<br />\(exists = docker ps -a --filter "name=^/\){Name}$" --format "{{.Names}}"<br />if (\(exists -eq \)Name) {<br />\(running = docker ps --filter "name=^/\){Name}$" --format "{{.Names}}"<br />if (\(running -ne \)Name) { docker start $Name | Out-Null }<br />}<br />}</p>
<p>function Set-FixedNetworkIP([string]$Name, [string]$RequiredIP) {<br />\(exists = docker ps -a --filter "name=^/\){Name}$" --format "{{.Names}}"<br />if (\(exists -ne \)Name) { Write-Warning "Container not found: $Name"; return }<br />\(inspect = docker inspect \)Name | ConvertFrom-Json<br />\(property = \)inspect[0].NetworkSettings.Networks.PSObject.Properties[$DockerNetwork]<br />\(currentIP = if (\)null -ne \(property) { \)property.Value.IPAddress } else { $null }<br />if (\(currentIP -eq \)RequiredIP) { return }<br />\(wasRunning = (docker inspect \)Name --format "{{.State.Running}}") -eq "true"<br />if (\(wasRunning) { docker stop \)Name | Out-Null }<br /># Disconnect only when the container is already attached to the network.<br /># This prevents Task Scheduler result 1 after a Windows restart.<br />if (\(null -ne \)property) {<br />docker network disconnect -f $DockerNetwork $Name | Out-Null<br />if ($LASTEXITCODE -ne 0) {<br />throw "Failed to disconnect $Name from $DockerNetwork."<br />}<br />}<br />docker network connect --ip $RequiredIP $DockerNetwork $Name<br />if ($LASTEXITCODE -ne 0) {<br />throw "Failed to connect $Name to $DockerNetwork using $RequiredIP."<br />}<br />if (\(wasRunning) { docker start \)Name | Out-Null }<br />}</p>
<p>if (-not (Test-Docker)) {<br />Start-Process "C:\Program Files\Docker\Docker\Docker Desktop.exe"<br />\(ready = \)false<br />foreach ($attempt in 1..60) {<br />Start-Sleep -Seconds 2<br />if (Test-Docker) { \(ready = \)true; break }<br />}<br />if (-not $ready) { throw "Docker Desktop did not become ready." }<br />}</p>
<p>docker network inspect \(DockerNetwork *&gt; \)null<br />if ($LASTEXITCODE -ne 0) {<br />docker network create --driver bridge --subnet 172.20.0.0/16 `<br />--gateway 172.20.0.1 $DockerNetwork | Out-Null<br />}</p>
<p>\(previousErrorActionPreference = \)ErrorActionPreference<br />$ErrorActionPreference = "Continue"<br />\(composeOutput = docker compose -f \)ComposeFile up -d 2&gt;&amp;1<br />\(composeExitCode = \)LASTEXITCODE<br />\(ErrorActionPreference = \)previousErrorActionPreference<br />\(composeOutput | ForEach-Object { Write-Host \)_ }<br />if ($composeExitCode -ne 0) {<br />throw "Docker Compose failed with exit code $composeExitCode."<br />}<br />Set-FixedNetworkIP "floci-floci-1" "172.20.0.6"</p>
<p>foreach ($attempt in 1..60) {<br />$health = docker inspect floci-floci-1 `<br />--format "{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}" 2&gt;$null<br />if ($health -eq "healthy") { break }<br />Start-Sleep -Seconds 2<br />}</p>
<p>Start-ContainerIfStopped $K3sContainer<br />Set-FixedNetworkIP $K3sContainer "172.20.0.4"</p>
<p>$RdsContainer = docker ps -a --format "{{.Names}}" |<br />Where-Object { $_ -like "floci-rds-*" } | Select-Object -First 1<br />if ($RdsContainer) {<br />Start-ContainerIfStopped $RdsContainer<br />Set-FixedNetworkIP $RdsContainer "172.20.0.3"<br />}</p>
<p>kubectl config use-context $KubeContext | Out-Null<br />\(nodeReady = \)false<br />\(previousErrorActionPreference = \)ErrorActionPreference<br />$ErrorActionPreference = "Continue"<br />try {<br />foreach ($attempt in 1..150) {<br />kubectl get nodes *&gt; $null<br />if ($LASTEXITCODE -eq 0) {<br />kubectl wait --for=condition=Ready node --all --timeout=10s *&gt; $null<br />if (\(LASTEXITCODE -eq 0) { \)nodeReady = $true; break }<br />}<br />Start-Sleep -Seconds 2<br />}<br />}<br />finally {<br />\(ErrorActionPreference = \)previousErrorActionPreference<br />}<br />if (-not $nodeReady) {<br />throw "The Kubernetes node did not become ready within five minutes."<br />}</p>
<p>kubectl rollout status deployment/ingress-nginx-controller `<br />-n ingress-nginx --timeout=180s</p>
<p>$portForward = Get-CimInstance Win32_Process | Where-Object {<br />\(_.Name -match "kubectl" -and \)_.CommandLine -match "port-forward" -and<br />$_.CommandLine -match "8080:80"<br />}<br />if (-not $portForward) {<br />Start-Process (Get-Command kubectl).Source `<br />-ArgumentList @("port-forward","--address","127.0.0.1",<br />"-n","ingress-nginx",<br />"service/ingress-nginx-controller","8080:80") `<br />-RedirectStandardOutput "$LogDirectory\ingress-port-forward.log" `<br />-RedirectStandardError "$LogDirectory\ingress-port-forward.error.log" `<br />-WindowStyle Hidden<br />Start-Sleep -Seconds 5<br />}</p>
<p>$ngrok = Get-CimInstance Win32_Process | Where-Object {<br />\(_.Name -eq "ngrok.exe" -and \)_.CommandLine -match "127.0.0.1:8080" -and<br />$_.CommandLine -match "default.internal"<br />}<br />if (-not $ngrok) {<br />Get-Process ngrok -ErrorAction SilentlyContinue | Stop-Process -Force<br />Start-Process $NgrokExe `<br />-ArgumentList @("http","<a href="http://127.0.0.1:8080">http://127.0.0.1:8080</a>",<br />"--url","<a href="https://default.internal">https://default.internal</a>",<br />"--log","$LogDirectory\ngrok.log","--log-format","json") `<br />-RedirectStandardOutput "$LogDirectory\ngrok-output.log" `<br />-RedirectStandardError "$LogDirectory\ngrok-error.log" `<br />-WindowStyle Hidden<br />Start-Sleep -Seconds 8<br />}</p>
<p>\(runtimeReady = \)false<br />foreach ($attempt in 1..60) {<br />\(pods = kubectl get pods -n \)Namespace -o json | ConvertFrom-Json<br />\(runtimePods = @(\)pods.items | Where-Object {<br />\(_.metadata.name -match "-master-" -and \)_.status.phase -eq "Running"<br />})<br />foreach ($pod in $runtimePods) {<br />\(statuses = @(\)pod.status.containerStatuses)<br />if ($statuses.Count -gt 0 -and<br />@(\(statuses | Where-Object { -not \)_.ready }).Count -eq 0) {<br />\(runtimeReady = \)true<br />Write-Host "Mendix runtime is ready: $($pod.metadata.name)"<br />break<br />}<br />}<br />if ($runtimeReady) { break }<br />Start-Sleep -Seconds 10<br />}</p>
<p>\(available = \)false<br />if ($runtimeReady) {<br />foreach ($attempt in 1..12) {<br />try {<br />\(response = Invoke-WebRequest -Uri \)PublicURL -UseBasicParsing -TimeoutSec 20<br />if (\(response.StatusCode -eq 200) { \)available = $true; break }<br />} catch { }<br />Start-Sleep -Seconds 10<br />}<br />}</p>
<p>if (-not $available) { throw "Public Mendix URL did not return HTTP 200." }<br />Write-Host "Floci Mendix lab is ready: $PublicURL" -ForegroundColor Green<br />kubectl get pods -n $Namespace</p>
</blockquote>
<h2>Validate the final script</h2>
<p>The final restart-safe version contains three important corrections. Set-FixedNetworkIP disconnects only when a container is already attached. Docker Compose and the Kubernetes readiness loop temporarily tolerate expected native stderr while retaining explicit exit-code checks. The port-forward binds to 127.0.0.1 and ngrok targets <a href="http://127.0.0.1:8080">http://127.0.0.1:8080</a>, avoiding the IPv6 localhost failure at ::1. The script waits up to 10 minutes for the runtime before validating the public URL.</p>
<blockquote>
<p>\(syntaxErrors = \)null<br />[System.Management.Automation.Language.Parser]::ParseFile(<br />"D:\Floci\scripts\Start-FlociLab.ps1",<br />[ref]$null,<br />[ref]$syntaxErrors<br />) | Out-Null<br />$syntaxErrors</p>
</blockquote>
<p>No output means the PowerShell syntax is valid. Run the script once before registering it.</p>
<blockquote>
<p>powershell.exe -NoProfile -ExecutionPolicy Bypass `<br />-File "D:\Floci\scripts\Start-FlociLab.ps1"</p>
</blockquote>
<h2>Create the hidden VBS launcher</h2>
<p>Save this file as D:\Floci\scripts\Start-FlociLab.vbs. WScript launches the PowerShell recovery script with window style 0, waits for its exit code, and records all startup output without leaving a visible terminal open.</p>
<blockquote>
<p>Set shell = CreateObject("WScript.Shell")</p>
<p>command = "powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command ""&amp; 'D:\Floci\scripts\Start-FlociLab.ps1' *&gt; 'D:\Floci\scripts\logs\scheduled-task.log'"""</p>
<p>exitCode = shell.Run(command, 0, True)</p>
<p>WScript.Quit exitCode</p>
</blockquote>
<h2>Run automatically at Windows sign in</h2>
<blockquote>
<p>$taskAction = New-ScheduledTaskAction `<br />-Execute "wscript.exe" `<br />-Argument '"D:\Floci\scripts\Start-FlociLab.vbs"'</p>
<p>$taskTrigger = New-ScheduledTaskTrigger `<br />-AtLogOn `<br />-User $env:USERNAME<br />$taskTrigger.Delay = "PT2M"</p>
<p>$taskSettings = New-ScheduledTaskSettingsSet `<br />-StartWhenAvailable `<br />-ExecutionTimeLimit ([TimeSpan]::Zero) `<br />-MultipleInstances IgnoreNew `<br />-Hidden</p>
<p>$taskPrincipal = New-ScheduledTaskPrincipal `<br />-UserId "$env:USERDOMAIN\env:USERNAME" `<br />-LogonType Interactive `<br />-RunLevel Highest</p>
<p>Register-ScheduledTask `<br />-TaskName "Start Floci Mendix Lab" `<br />-Action $taskAction `<br />-Trigger $taskTrigger `<br />-Settings $taskSettings `<br />-Principal $taskPrincipal `<br />-Description "Restores the Floci Mendix lab two minutes after Windows sign-in" `<br />-Force</p>
<p># Disable the obsolete task that opened a visible PowerShell window.<br />Disable-ScheduledTask -TaskName "Mendix Local Startup"</p>
<p>Start-ScheduledTask -TaskName "Start Floci Mendix Lab"<br />Start-Sleep -Seconds 30<br />Get-ScheduledTaskInfo -TaskName "Start Floci Mendix Lab" |<br />Select-Object LastRunTime, LastTaskResult, NextRunTime</p>
</blockquote>
<p>Verified final result on 13 September 2026: LastTaskResult was 0 after an actual Windows restart. Docker starts at sign-in, the recovery task begins after a two-minute delay, the VBS launcher keeps PowerShell hidden, and the IPv4 port-forward and ngrok tunnel run without visible windows. The Mendix runtime reached 2/2 Running, Agent and Operator reached 1/1 Running, and the public URL returned HTTP 200.</p>
<h1>Final validation and operating notes</h1>
<table>
<thead>
<tr>
<th><strong>Check</strong></th>
<th><strong>Expected result</strong></th>
</tr>
</thead>
<tbody><tr>
<td>docker inspect floci-floci-1</td>
<td>Healthy; floci_default=172.20.0.6</td>
</tr>
<tr>
<td>docker inspect floci-rds-*</td>
<td>floci_default=172.20.0.3</td>
</tr>
<tr>
<td>docker inspect K3s container</td>
<td>floci_default=172.20.0.4</td>
</tr>
<tr>
<td>kubectl get nodes</td>
<td>One Ready control-plane node</td>
</tr>
<tr>
<td>kubectl get pods -n mendix-floci</td>
<td>Agent 1/1, Operator 1/1, runtime 2/2</td>
</tr>
<tr>
<td>kubectl get pods -n ingress-nginx</td>
<td>Controller 1/1 Running</td>
</tr>
<tr>
<td>Mendix Portal</td>
<td>Network, Storage, Database, Service Account, Build, Runtime green</td>
</tr>
<tr>
<td>Invoke-WebRequest public URL</td>
<td>HTTP 200 OK</td>
</tr>
<tr>
<td>Scheduled task</td>
<td>LastTaskResult 0</td>
</tr>
</tbody></table>
<h2>Normal startup behavior</h2>
<ul>
<li><p>The Kubernetes API and containers can take several minutes to become ready after Docker Desktop starts.</p>
</li>
<li><p>A runtime pod can temporarily report readiness HTTP 500 while Mendix initializes.</p>
</li>
<li><p>The public URL is unavailable until both kubectl port-forward and the ngrok agent are running.</p>
</li>
<li><p>Use 127.0.0.1 explicitly for both port-forward and ngrok; localhost can resolve to IPv6 ::1 and cause a refused private-leg connection.</p>
</li>
<li><p>The exact free ngrok hostname supports one environment at a time. Multiple environment subdomains require a wildcard-capable domain or separate endpoints.</p>
</li>
<li><p>The startup script writes host-process logs under D:\Floci\scripts\logs. Task Scheduler may remain Running while the script waits; LastTaskResult becomes 0 after completion.</p>
</li>
<li><p>Keep Mendix Local Startup disabled. It is the obsolete duplicate task that opened a visible Administrator PowerShell window.</p>
</li>
</ul>
<h2>Safe recovery order</h2>
<blockquote>
<p><strong>1.</strong> Run D:\Floci\scripts\Start-FlociLab.ps1.</p>
<p><strong>2.</strong> Confirm the three fixed Docker addresses.</p>
<p><strong>3.</strong> Confirm the floci-mendix context and Ready node.</p>
<p><strong>4.</strong> Confirm ingress-nginx, Agent, Operator, and runtime pods.</p>
<p><strong>5.</strong> Inspect only the failing component logs; never publish full secrets or unredacted custom resource YAML.</p>
<p><strong>6.</strong> Validate the public URL with Invoke-WebRequest.</p>
</blockquote>
]]></content:encoded></item></channel></rss>