Expose a site behind local NGINX
Expose a site served by local NGINX through a Horizon tunnel, including a server_name virtual host such as mysite.test.
Share a site that NGINX serves on your machine, with an HTTPS URL. You tunnel to NGINX, not to the app behind it.
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. - NGINX running locally. The examples use port 8080.
Check which Host NGINX expects
NGINX tests only the Host header to pick a server. If the value matches no server_name, NGINX uses the default server for that port. The Horizon CLI sets Host to the host of the URL you give it, so the URL decides which server answers.
This site answers to mysite.test:
server {
listen 8080;
server_name mysite.test;
root /var/www/mysite;
}Start a tunnel to NGINX's port
If you have one site on the port, or the default server is the one you want, tunnel to localhost:
hrzn tunnel http://localhost:8080 -s my-appIf a server_name picks your site, tunnel to that hostname. It must resolve on your machine, for example through an entry in /etc/hosts.
hrzn tunnel http://mysite.test:8080 -s my-appHorizon then sends Host: mysite.test:8080. NGINX matches mysite.test.
HORIZON: Tunnel connected
URL https://my-app.hrzn.run (reserved)
Forwarding http://mysite.test:8080
Request log https://hrzn.run/dashboard/tunnels/my-appUse -s with a subdomain you reserved. Reserved subdomains are a paid feature, see Pricing. Keep this terminal open.
Open the URL
Open https://my-app.hrzn.run. A first-time browser visitor sees the Before you continue page. Select Continue to site.
Check it works
The Horizon terminal prints a line per request:
GET 200 /The public host arrives at NGINX in X-Forwarded-Host. If NGINX proxies to an app behind it, pass the header on with proxy_set_header. NGINX's default for Host in a proxied request is $proxy_host, so set the headers you need:
location / {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $http_x_forwarded_host;
}Troubleshooting
The wrong site answers
NGINX routed the request to the default server for the port because Host matched no server_name. Tunnel to the hostname in server_name, as in hrzn tunnel http://mysite.test:8080.
The hostname doesn't resolve
The Horizon CLI connects from your machine, so mysite.test must resolve there. Add it to /etc/hosts, then run the tunnel command again.
502 Bad Gateway
NGINX can't reach the app behind proxy_pass. Check that the app listens on the address in proxy_pass. The tunnel is working, because the response comes from NGINX.
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.
Next steps
- Read NGINX's page on how it processes a request.
Expose a Docker Compose service
Expose a Docker Compose service to the internet with a Horizon tunnel, using the service's published port.
Share a MAMP, WAMP or XAMPP virtual host
Share a MAMP, WAMP or XAMPP virtual host such as mysite.test with a Horizon tunnel by passing the host name to hrzn tunnel.