Problem
Build a vagrant development environment that will serve an rails application that works on multiple subdomains. Moreover that application consists of multiple smaller apps that all are running with a single domain.
example.dev
-> Application #1app.example.dev
-> Application #2<any other subdomain>.example.dev
-> Application #3
Let’s assume we’re using .dev
domains, because we’re used to pow. Meaning those routing should work within vagrant machine and same subdomains should work exactly same way on our local machine.
Solution - nginx & dnsmasq
(I assume you’re running some kind of ubuntu-based distro, paths may vary between distros)
Install nginx & dnsmasq. Edit file /etc/dnsmasq.d/dev-tld
as follows:
# /etc/dnsmasq.d/dev-tld
local=/dev/
address=/dev/127.0.0.1
Restart dnsmasq
service. This rule will forward traffic from .dev domains to your localhost - and this is exactly what we want.
Now let’s configure nginx, following the scenario above we will need configuration for three apps. We will need some kind of server (thin, puma, unicorn, whatever) that will listen on unix socket. In our nginx config / sites-enabled we need:
upstream app1 {
server unix:/apps/app1/tmp/some_rack_server.sock;
}
server {
listen 80;
server_name example.dev;
root /apps/app1/public;
location / {
proxy_pass http://app1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
upstream app2 {
server unix:/apps/app2/tmp/some_rack_server.sock;
}
server {
listen 80;
server_name app.example.dev;
root /apps/app2/public;
location / {
proxy_pass http://app2;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
upstream app3 {
server unix:/apps/app3/tmp/some_rack_server.sock;
}
server {
listen 80;
server_name *.example.dev;
root /apps/app3/public;
location / {
proxy_pass http://app3;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Nging will listen on port 80 and forward request according to our needs. Traffic from example.dev
will be served by our first app (app1), app.example.dev
will be served by app2 and any other traffic (*.example.dev
) will go through app3.
So this works, nice & easy. We have 3 rack servers listing on UNIX sockets backed by nginx that routes everything. From vagrant box you can access all .dev
domains, so far - very cool.
Next step - accessing .dev subdomains from local machine
It’s nice, but it’s not very useful at this point really - we have no way for accessing example.dev
(or any of it’s subdomains) from our local machine. But there is already solution for that - some smart folks already created tools for us that solves this problem.
First we need to route traffic from ninx in vagrant (port 80) to our machine, in Vagrantfile you need:
Vagrant.configure("2") do |config|
# ...
config.vm.network :forwarded_port, guest: 80, host: 8080 # or any other port available on your machine
Note: don’t forget to restart your vagrant vm after making changes to Vagrantfile.
Now, depending on what system you are using:
on Mac you have already mentioned pow, after installation you go to
~/.pow
and type:echo 8080 > example
on Linux you have prax, very similarly - after installation you to to
~/.prax
and type the same thing
pow/prax will now forward traffic from *.example.dev
on your local machine to port 8080 - so basically this will be handled by nginx in vagrant and it just works with our subdomains setup. Magic.
References: Port Proxying (pow), Per-app port forwarding (prax), Vagrant - port forwarding, Rails App With Puma and NGINX