How Muppy Exposes Your Application¶
TLS is terminated before your server. Your process serves plain HTTP, on one port, to a reverse proxy that already holds the certificate. Everything else on this page is about names: which ones your application answers to, and which one Muppy calls the URL.
Two readers come to this page, and they do not see the same screen.
| You are | You see | Read |
|---|---|---|
| a developer building the application | the App Server's Application URL, its IDE, and /etc/muppy.env |
The chain → The two URLs you are given |
| a developer administering the App Server | the full Network tab | all of it |
The chain¶
Visitor → Cloudflare → Sunray Zero-Trust → Traefik → localhost:${APP_HTTP_PORT}
- Cloudflare — optional, and only for a public URL. Anti-DDoS, WAF and cache, the origin IP hidden, and the edge holds the certificate.
- Sunray Zero-Trust — optional. A Traefik middleware that asks who the visitor is before your application ever sees the request.
- Traefik — the reverse proxy. It terminates TLS and matches the requested host name against its routers.
- Your process — plain HTTP on
${APP_HTTP_PORT}.
Your process binds one port¶
${APP_HTTP_PORT} is the only port that receives traffic from the outside. Read it
from /etc/muppy.env; Muppy resolves it from the App Server's Exposed Ports,
preferring the one whose Service is http-service, then odoo, then the first.
Do not serve HTTPS and do not install a second reverse proxy. Both are already upstream.
Several concerns share one URL by path routing — /api/*, /admin/*,
/webhooks/stripe. For a local port that only you need to reach, use the Code
Server proxy at <codr-url>/proxy/<N>/; it is reachable by the authenticated user
only.
The two URLs you are given¶
/etc/muppy.env carries two, and they are not the same thing.
| Variable | Filled from | What it means |
|---|---|---|
APP_PRIMARY_URL |
the direct application | the App Server's own URL. Empty when it has no direct application |
APP_LOADBALANCER_URL |
the public route | the public entry point: the Default LoadBalancer URL when someone has set one, otherwise the application of the first Public Exposure Definition. Empty when the server has neither, and consumers then fall back to APP_PRIMARY_URL |
The two answer different questions, so they routinely differ: one is the name the server answers to directly, the other is the name the public reaches it by.
Default LoadBalancer URL is yours. Nothing writes it automatically, so whatever you put there survives every reconfiguration — that is how you force the public URL. Leave it empty and the public route comes from the first Public Exposure Definition instead.
One name, one Traefik Application¶
A Traefik Application is one name, one configuration file on the Traefik server, one set of routers. Traefik watches that directory, so changing an application needs no restart.
An App Server usually has more than one:
- the direct application — always created, named from the Direct URL FQDN Generator, resolving to the host's own address;
- one public application per attached Traefik Application Definition — the route that goes through Cloudflare.
The definition's Public Exposure flag is what makes an application a candidate for Default LoadBalancer URL, and what puts it ahead of the direct one when Muppy decides which URL is the App Server's.
How the name itself is built — the generators, and why a public name drops the host and the company — is in Tenants, Domains and Host Names. Putting your own name in front of it is Custom Domains.
The Network tab, control by control¶
| Control | What it does |
|---|---|
| External App. URL | Deprecated, scheduled for removal. The application's URL when something other than Muppy publishes it. Use a Traefik Application Definition instead. |
| Activate Reverse Proxy | Off means Muppy removes this App Server's Traefik Applications instead of maintaining them. |
| Documentation | Opens this page. |
| (re)Configure 'Traefik Applications' | Reconciles the applications with the definitions, uploads each configuration to the Traefik server, and creates DNS records where the strategy asks for them. Run it after changing anything below. |
| Remove 'Traefik Applications' | Stops serving: the configuration files are deleted and the applications deactivated. The records stay — only deprovisioning the App Server deletes them. |
| Traefik Server | The reverse proxy that serves this App Server, and the source of the default DNS domain. |
| Traefik App Config Template | The template rendered into the direct application's configuration file. |
| Direct URL FQDN Generator | Builds the host name of the direct URL. See Network Configuration. |
| Default LoadBalancer URL | Your override of the public URL, set with Set as default LB and never written automatically. It wins over the Public Exposure Definition. Left empty, the public route falls back to that Definition — both for the button and for APP_LOADBALANCER_URL. |
| Traefik Applications | The generated applications, read-only here. URL is the name served; Custom Domain (CNAME) is your own name in front of it; Use Let's Encrypt says who issues the certificate. |
| ↳ Set as default LB | Copies that row's URL into Default LoadBalancer URL. Nothing else — no Traefik, no DNS. Choosing a non-public application is allowed and warns you, because the next reconfiguration will not replace it. |
| ↳ Edit | Opens the application, where Custom Domain, the whitelist and the certificate live. |
| Traefik Application Definitions | The blueprints attached to this App Server. Sequence orders them; Public Exposure marks the one that provides the default public URL. |
| Exposed Ports | The ports your services listen on. They feed both Traefik's routing and ${APP_HTTP_PORT}. |
| ↳ Sync Exposed Ports with App. Definition | Copies the ports declared on the App Definition onto this App Server. |
| ↳ Sync Exposed Ports with Host | Copies them onto the host, which is what Traefik reads. A reconfiguration does this for you. |
| DNS Records | The records the Traefik Applications created, with their Proxied state. |
| ↳ Delete DNS Records | Deletes them. The next reconfiguration recreates them where the strategy asks. |
| SSH (with Tailscale) | The private SSH path to the box, independent of everything above. |
Which button opens which URL¶
The App Server's button box carries two. Each has one source and one fallback, and disappears when it has neither — rather than offering a control that opens nothing.
| Button | Opens | Falls back to |
|---|---|---|
| Open App. Direct URL | the application the App Server generates for itself, from its Traefik App Config Template and its Direct URL FQDN Generator | the application of the first attached Definition that is not Public Exposure |
| Open Load Balancer URL | the Default LoadBalancer URL field | the application of the first attached Definition flagged Public Exposure |
These are the same two routes as the environment variables above: Open App. Direct URL opens
APP_PRIMARY_URL, Open Load Balancer URL opens APP_LOADBALANCER_URL.
"First" is the order of the Traefik Application Definitions list, which its drag handle sets.
The two are independent: on an App Server that has both a direct route and a public one, they open two different URLs, and that is the point.
Where to go next¶
- Network Configuration — name generation, and public URLs behind Cloudflare.
- Tenants, Domains and Host Names — how a host name is built.
- Custom Domains — serving the application under your own name.
- Designing Your mgx — what belongs on the server at all.
- services.yml Service Definitions Guide — declaring the process that binds the port.