This is an experimental Sinatra application demonstrating how to configure a custom local hostname for development.
This project explores how to set up a simple Sinatra application that responds to requests using a custom .local hostname instead of just localhost or 127.0.0.1. This is useful for:
- Testing applications with custom domain names locally
- Simulating production-like URLs in development
- Working with multiple local projects using different hostnames
To make hello-world-socks5h.local resolve to your local machine, we added an entry to /etc/hosts:
127.0.0.1 hello-world-socks5h.local
The bin/setup script automates this by:
- Checking if the entry already exists
- If not, using
sudoto append the entry to/etc/hosts - Prompting for your password when needed
Manual alternative:
echo "127.0.0.1 hello-world-socks5h.local" | sudo tee -a /etc/hostsSinatra 4.x introduced stricter host authorization via Rack::Protection::HostAuthorization middleware. By default, it blocks requests with unrecognized Host headers to prevent DNS rebinding and host header attacks.
When accessing the app via http://hello-world-socks5h.local:9292/, the request would be blocked with:
Host not permitted
W, attack prevented by Rack::Protection::HostAuthorization
We configured Sinatra to explicitly permit our custom hostname in app.rb:
configure :development do
set :host_authorization, permitted_hosts: [
'127.0.0.1',
'localhost',
'hello-world-socks5h.local'
]
endThis tells Rack::Protection to allow requests with these Host headers.
Alternative approaches:
- Allow all hosts in development (less secure):
set :host_authorization, allow_if: ->(env) { true }
- Disable protection entirely (not recommended):
set :protection, false
We also configured Puma to bind to all network interfaces (0.0.0.0) instead of just 127.0.0.1 in config/puma.rb:
bind 'tcp://0.0.0.0:9292'This ensures Puma accepts connections regardless of which hostname is used in the request.
-
Install Ruby 4.0.0 (using mise):
mise install
-
Run the setup script:
./bin/setup
This will:
- Install Ruby via mise
- Install gem dependencies via Bundler
- Add the custom hostname to
/etc/hosts(requires sudo)
Start the development server:
./bin/devThe app will be available at:
- IP address: http://127.0.0.1:9292/
- Custom hostname: http://hello-world-socks5h.local:9292/
Both URLs will return: Hello World!
Verify both URLs work:
# Test via IP
curl http://127.0.0.1:9292/
# Test via custom hostname
curl http://hello-world-socks5h.local:9292/Both should return Hello World!
.
├── .tool-versions # Ruby version for mise
├── Gemfile # Ruby dependencies
├── app.rb # Sinatra application with host authorization config
├── config.ru # Rack configuration
├── config/
│ └── puma.rb # Puma web server configuration
├── bin/
│ ├── setup # Setup script (installs deps, configures hosts)
│ └── dev # Development server start script
└── README.md # This file
-
Custom hostnames require two configurations:
- DNS resolution (via
/etc/hosts) - Application-level permission (via Sinatra's
host_authorization)
- DNS resolution (via
-
Sinatra 4.x has stricter defaults:
- Host authorization is enabled by default
- Custom hostnames must be explicitly permitted
- This is a security feature to prevent host header attacks
-
Puma binding matters:
- Binding to
0.0.0.0allows requests from any hostname - Binding to
127.0.0.1only allows localhost traffic
- Binding to
- Ruby: 4.0.0
- Sinatra: ~> 4.0
- Puma: ~> 6.0
- Rackup: ~> 2.0
- Standard (development): ~> 1.0
Run StandardRB to check code style:
bundle exec standardrbAuto-fix issues:
bundle exec standardrb --fix