Share a FastAPI app
Share a FastAPI app with a Horizon tunnel, open the /docs Swagger UI on the public URL, and fix redirects that point at localhost.
Share your FastAPI app with a public HTTPS URL, including the interactive /docs page.
Before you begin
- Node.js 18 or later
- A Horizon account and the CLI (see Getting started)
- A reserved subdomain for
-s. Reserve one on the Subdomains page. - A FastAPI app in
main.pyand Uvicorn installed
Start a tunnel
Use -s with a subdomain you reserved. Without it, the subdomain is random and changes every run. Reserved subdomains are a paid feature, see Pricing.
hrzn tunnel http://localhost:8000 -s my-appHORIZON: Tunnel connected
URL https://my-app.hrzn.run (reserved)
Forwarding http://localhost:8000
Request log https://hrzn.run/dashboard/tunnels/my-appYour public URL is https://my-app.hrzn.run. Keep this terminal open.
Open the Swagger UI
Open https://my-app.hrzn.run/docs. The page loads /openapi.json from the same address, so Try it out sends requests to the public URL. You don't need root_path. It's for apps served under a path prefix such as /api/v1.
Check it works
Open https://my-app.hrzn.run/docs. On the first visit Horizon shows a Before you continue page. Select Continue to site. Swagger UI lists your routes. Expand one, select Try it out, then Execute.
The Horizon terminal prints one line per request:
GET 200 /docs
GET 200 /openapi.json
GET 200 /items/Troubleshooting
A redirect goes to http://localhost:8000
FastAPI redirects /items to /items/ when you declare the route with a trailing slash. The redirect builds its address from the Host header, which the CLI sets to localhost:8000. The browser then follows a link to your own machine.
Request the exact path, /items/, or declare the route without the trailing slash. Check the Location header with curl -i https://my-app.hrzn.run/items.
Do I need --proxy-headers or --forwarded-allow-ips?
No. --proxy-headers is on by default, and Uvicorn trusts 127.0.0.1 and ::1, which is where the CLI connects from. Uvicorn only reads X-Forwarded-Proto and X-Forwarded-For. It ignores X-Forwarded-Host, and it skips an X-Forwarded-Proto value like https,http. So the flags don't change the host or scheme your app sees.
The URL changed after a restart
You started the tunnel without -s, so Horizon gave you a new random subdomain. Restart with -s my-app and the URL stays the same. -s needs a subdomain you reserved, see Pricing.
Nothing reaches your app
- Check that the Horizon terminal is still running. If its last line is
Connection lost. Reconnecting…, wait forReconnected. - Check that Uvicorn listens on port 8000, the port in your
hrzn tunnelcommand.
Next steps
- Read FastAPI's guide to running behind a proxy.
- Share a different stack: Flask or Django.