Michael Dyrynda
Home Blog Podcasts
 
Dead simple domain mapping in Laravel Homestead February 13th, 2016

Introduction

About a month ago, Freek Van der Herten wrote some Laravel Homestead tips on his blog. The item that stood out for me was avoiding having to edit the hosts file. I won't go into much more detail here, but essentially this uses a utility called dnsmasq to tell your computer to resolve configured domains locally.

Have a read over Freek's article and get dnsmasq up and running and we'll continue.

Update May 6, 2016: I'd advise against the use of *.dev due to Google's proposed usage and potential name collisions. Since writing this post, I've switched to *.test; the remainder of the post remains unchanged.

Wildcard hosts

Now that you've setup dnsmasq, you can resolve *.test to your Homestead machine easily, but you still need that manual step of either configuring a new domain in your Homestead.yaml file or using the serve command within the virtual machine itself.

Whilst neither of these methods take a particularly long time to complete, it's still a few seconds of repetition that can be avoided with some tweaking of your default nginx configuration using wildcard hosts.

What we'll be doing, is telling nginx to listen for anything sent to it that isn't explicitly configured and look for the domain name in your (default) /home/vagrant/Code directory.

Configuring nginx

Create a new file called /etc/nginx/sites-available/test_domains and add the following:

1server {
2 listen 80 default_server;
3 # Only if you want SSL
4 # listen 443 ssl;
5 server_name _;
6 root /home/vagrant/Code/$host/public;
7 
8 index index.html index.htm index.php;
9 
10 charset utf-8;
11 
12 location / {
13 try_files $uri $uri/ /index.php?$query_string;
14 }
15 
16 location = /favicon.ico { access_log off; log_not_found off; }
17 location = /robots.txt { access_log off; log_not_found off; }
18 
19 access_log off;
20 error_log /var/log/nginx/test_domains-error.log error;
21 
22 sendfile off;
23 
24 client_max_body_size 100m;
25 
26 location ~ \.php$ {
27 fastcgi_split_path_info ^(.+\.php)(/.+)$;
28 fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
29 fastcgi_index index.php;
30 include fastcgi_params;
31 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
32 fastcgi_intercept_errors off;
33 fastcgi_buffer_size 16k;
34 fastcgi_buffers 4 16k;
35 fastcgi_connect_timeout 300;
36 fastcgi_send_timeout 300;
37 fastcgi_read_timeout 300;
38 }
39 
40 location ~ /\.ht {
41 deny all;
42 }
43 
44 # Only if you want SSL
45 # ssl_certificate /etc/nginx/ssl/test_domains.crt;
46 # ssl_certificate_key /etc/nginx/ssl/test_domains.key;
47 }

The bulk of this config is the default created by Homestead using the serve or Homestead.yaml provisioning methods, but take note of a couple of key changes:

1server {
2 listen 80 default_server;
3 listen 443 ssl;
4 server_name _;
5 root /home/vagrant/Code/$host/public;
6 
7 # ...
8 
9 error_log /var/log/nginx/test_domains-error.log error;
10 
11 # ...
12 
13 # Only if you want SSL
14 # ssl_certificate /etc/nginx/ssl/test_domains.crt;
15 # ssl_certificate_key /etc/nginx/ssl/test_domains.key;
16 }

This tells nginx to listen on port 80 (HTTP) and 443 (HTTPS), setting 80 as the default_server. We can then use the special variable for server_name _; in order to catch domains names not explicitly configured.

Next, the root variable is set to /home/vagrant/Code/$host/public. nginx will convert $host to the domain name that is being used for the request. For example, if you want to use sometestdomain.test, you would configure a directory with the domain name in /home/vagrant/Code/sometestdomain.test, which would contain a public directory.

This means that providing you name your project directories <something>.test and map their parent directory - default ~/Code - directly to /home/vagrant/Code, you won't have to configure a standard Laravel environment manually again.

Next, link the test_domains configuration to nginx's sites-enabled directory:

1$ cd /etc/nginx/sites-enabled
2$ sudo ln -s /etc/nginx/sites-available/test_domains ./test_domains

Lastly, restart nginx - sudo service nginx restart - and you will now be able to get to any *.test domain at http://<something>.test, as long as a directory exists in /home/vagrant/Code named the same as your domain and contains a public directory.

Configuring wildcard SSL

For those of who like to test with SSL, you can configure a wildcard SSL certificate as well.

From your Homestead environment:

1$ sudo openssl genrsa -out /etc/nginx/ssl/test_domains.key 2048
2$ sudo openssl req -new -key /etc/nginx/ssl/test_domains.key -out /etc/nginx/ssl/test_domains.csr
3Country Name (2 letter code) [AU]:
4State or Province Name (full name) [Some-State]:South Australia
5Locality Name (eg, city) []:Adelaide
6Organization Name (eg, company) [Internet Widgits Pty Ltd]:
7Organizational Unit Name (eg, section) []:
8Common Name (e.g. server FQDN or YOUR name) []:*.test
9Email Address []:
10$ sudo openssl x509 -req -days 365 -in /etc/nginx/ssl/test_domains.csr -signkey /etc/nginx/ssl/test_domains.key -out /etc/nginx/ssl/test_domains.crt

You can now uncomment the two SSL configuration lines at the end of the /etc/nginx/sites-available/test_domains file and restart nginx again.

Conclusion

Keep in mind that when using a self-signed certificate, your browser will likely complain about it initially, but you will be able to 'continue anyway' after the first visit.

The last thing to note, is that nginx doesn't support variables in the error_log configuration option. This means that we can't easily separate each host's error messages into separate files, however, as you're working in a local environment, the chances of you working in multiple sites simultaneously means this shouldn't be too much of an issue.

Further reading

I'm a real developer ™
Michael Dyrynda

@michaeldyrynda

I am a software developer specialising in PHP and the Laravel Framework, and a freelancer, blogger, and podcaster by night.

Proudly hosted with Vultr

Syntax highlighting by Torchlight