Tools: The Magic of lvh.me: Testing Rails Subdomains in Development

Tools: The Magic of lvh.me: Testing Rails Subdomains in Development

Source: Dev.to

The /etc/hosts Headache ## What is lvh.me? ## Step 1: The Rails Security Barrier ## Step 2: Accessing your App ## Step 3: Handling Subdomains in Code ## Step 4: Session & Cookie Sharing ## Bonus: SSL with Puma-dev ## Summary If you are building a SaaS that uses subdomains (like app.mysite.com or tenant.mysite.com), testing them locally is usually a pain. The traditional way is to edit your /etc/hosts file: This is tedious, requires sudo privileges, and you have to remember to do it for every new tenant or project. There is a better way. It’s called lvh.me. lvh.me (Local Virtual Host) is a free service that simply points its DNS "A" record to 127.0.0.1. Because it is a real registered domain name, it supports wildcards. This means: You don't have to install anything. You don't have to configure any DNS. It just works. Since Rails 6, there is a security feature that blocks "Host Header Attacks." If you try to visit http://lvh.me:3000 right now, Rails will show you a "Blocked Host" error page. You need to whitelist the domain in your development configuration: Note the dot before lvh.me - this is the wildcard that allows any subdomain. Restart your Rails server. Now, instead of localhost:3000, open your browser and go to: If you want to test your subdomain logic: http://app.lvh.me:3000 http://blog.lvh.me:3000 If you are using the routing constraints we discussed in the previous article, Rails will now correctly identify the subdomain. You can test this in your controller: If you need to stay logged in while moving between lvh.me and app.lvh.me, ensure your session store is configured to handle the domain correctly: Why tld_length: 2? Standard Rails assumes a TLD like .com or .org (length 1). Since lvh.me has two parts, you tell Rails to look two levels deep to find the "root" domain. If your app requires HTTPS locally (for example, if you are testing Stripe webhooks or Secure Cookies), lvh.me might not be enough because it doesn't provide an SSL certificate for your local machine. In that case, look into Puma-dev. It acts as a local DNS server and provides a self-signed SSL certificate for .test domains. But for 90% of development work, lvh.me is the fastest "zero-config" solution. Do you use lvh.me or do you prefer puma-dev? Share your local setup tips below! πŸ‘‡ Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK: 127.0.0.1 mysite.local 127.0.0.1 app.mysite.local Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: 127.0.0.1 mysite.local 127.0.0.1 app.mysite.local CODE_BLOCK: 127.0.0.1 mysite.local 127.0.0.1 app.mysite.local COMMAND_BLOCK: # config/environments/development.rb # Allow the main domain and all subdomains config.hosts << ".lvh.me" Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: # config/environments/development.rb # Allow the main domain and all subdomains config.hosts << ".lvh.me" COMMAND_BLOCK: # config/environments/development.rb # Allow the main domain and all subdomains config.hosts << ".lvh.me" CODE_BLOCK: class ApplicationController < ActionController::Base before_action :check_subdomain def check_subdomain puts "Current subdomain: #{request.subdomain}" end end Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: class ApplicationController < ActionController::Base before_action :check_subdomain def check_subdomain puts "Current subdomain: #{request.subdomain}" end end CODE_BLOCK: class ApplicationController < ActionController::Base before_action :check_subdomain def check_subdomain puts "Current subdomain: #{request.subdomain}" end end COMMAND_BLOCK: # config/initializers/session_store.rb Rails.application.config.session_store :cookie_store, key: '_your_app_session', domain: :all, tld_length: 2 # This is important for lvh.me Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: # config/initializers/session_store.rb Rails.application.config.session_store :cookie_store, key: '_your_app_session', domain: :all, tld_length: 2 # This is important for lvh.me COMMAND_BLOCK: # config/initializers/session_store.rb Rails.application.config.session_store :cookie_store, key: '_your_app_session', domain: :all, tld_length: 2 # This is important for lvh.me - lvh.me points to 127.0.0.1 - app.lvh.me points to 127.0.0.1 - any-thing-you-want.lvh.me points to 127.0.0.1 - Stop manually editing /etc/hosts. - Add config.hosts << ".lvh.me" to your development config. - Use any subdomain you want instantly.