Horizon

Share a Rails dev server

Share a Rails dev server with a Horizon tunnel, and fix the "Blocked hosts" page with config.hosts and the CSRF origin check.

Share your Rails development server with a public HTTPS URL, with host checks and POST forms working.

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 Rails app you can run with bin/rails server

Start the dev server

Rails listens on port 3000 by default.

bin/rails server

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:3000 -s my-app
Output
HORIZON: Tunnel connected
  URL          https://my-app.hrzn.run (reserved)
  Forwarding   http://localhost:3000
  Request log  https://hrzn.run/dashboard/tunnels/my-app

Your public URL is https://my-app.hrzn.run. Keep this terminal open.

Allow the public host

The CLI sets Host to localhost:3000, but the public host still arrives in X-Forwarded-Host. Rails' host authorization checks both headers. The development defaults allow localhost, .localhost, .test and IP addresses, so my-app.hrzn.run is blocked.

Add the public host to config.hosts. A leading dot allows the domain and all its subdomains, so ".hrzn.run" also covers a random subdomain.

config/environments/development.rb
Rails.application.configure do
  config.hosts << "my-app.hrzn.run"
end

Restart bin/rails server after you edit the file.

Check it works

Open https://my-app.hrzn.run in a browser. On the first visit Horizon shows a Before you continue page. Select Continue to site. Your app renders instead of the Rails host error.

Then submit a form. The Horizon terminal prints one line per request:

Output
  GET     200  /
  POST    302  /sessions

Troubleshooting

Blocked hosts: my-app.hrzn.run

Rails shows this page, with a 403 status, when the host isn't in config.hosts. The page lists the exact line to add, config.hosts << "my-app.hrzn.run". Add it to config/environments/development.rb and restart the server.

HTTP Origin header (https://my-app.hrzn.run) didn't match request.base_url

With forgery_protection_origin_check on, Rails compares the Origin header of a POST with request.base_url. Rails builds base_url from X-Forwarded-Host and the scheme it sees. The two differ when the app sees http instead of https, for example request.base_url (http://my-app.hrzn.run).

For development, turn the origin check off. The authenticity token check stays on.

config/environments/development.rb
Rails.application.configure do
  config.action_controller.forgery_protection_origin_check = false
end

Restart the server. Leave the setting on in production.

Can't verify CSRF token authenticity

The form's token doesn't match the session. Reload the form through the public URL, so the session cookie and the token come from the same site.

Nothing reaches your app

  • Check that the Horizon terminal is still running. If its last line is Connection lost. Reconnecting…, wait for Reconnected.
  • Check that Rails listens on port 3000, the port in your hrzn tunnel command.

Next steps

On this page