Addresses and access
Every app has a public address, a preview address per version and an internal address. You can leave it public or protect it with a password.
The three addresses#
An address is made of the address label and your organization's name. All of them use HTTPS.
| Address | Who can open it | Example |
|---|---|---|
| Public address | Anyone; a password if the app is private | https://order-api--acme.hosting.agentlab.run |
| Version preview address | Anyone with the address; a password if the app is private | One per version, shown next to it |
| Internal address | Only your organization's apps; a browser can't open it | https://order-api--acme.internal-hosting.agentlab.run |
Address labels#
You choose the address label when you create the app. It uses lowercase letters, numbers and hyphens. Once used, a label stays with your organization, and nobody else gets it even after the app is permanently deleted.
Public or private#
Choose the app's access in its Settings:
| Option | Effect |
|---|---|
| Public | Anyone with the address can view it. |
| Private | Every address of the app (the public address and each version's preview address) shows a password page first. |
The console generates the password and shows it once. If it's lost, generate a new one.
Private apps are served without the CDN
That's fine for a handful of reviewers, but not for heavy traffic.
Calling another app#
Apps in the same organization call each other at their internal addresses:
- Only your organization's apps can call it, from inside the platform. Other organizations, builds and the internet can't.
- The certificate is publicly trusted, so a default HTTP client works.
- A call reaches the live version.
- The internal address has no password page. Protect sensitive endpoints in your code.
A request that arrives on the internal address carries an X-Franky-Caller-App header with the address label of the app that sent it. Trust it only when Host is the internal domain:
const internal = req.headers.host?.endsWith(".internal-hosting.agentlab.run");
const caller = internal ? req.headers["x-franky-caller-app"] : undefined;
if (req.url.startsWith("/admin") && caller !== "billing-worker") {
res.writeHead(403).end();
return;
}