Laravel Nginx Wildcard Setup

A Laravel Nginx Wildcard Setup was needed to accommodate the generation of (sub) domains per project. Here the story how we started out and where we ended up at. This will be interesting for people setting up wildcards for Nginx and people using a Laravel application on Nginx that needs wildcard capability.

Initial Nginx Setup

For the Digital Ocean droplet we had a pretty standard /etc/nginx/nginx.conf file. It indicates

  • the user used,
  • log location,
  • work_processes
  • http block

and so on. Here is its content:

user www-data;
 
 error_log /var/log/nginx/error.log warn;
 pid /run/nginx.pid;
 
 worker_processes 1;
 
 events {
 worker_connections 1024;
 multi_accept off;
 }
 
 
 http {
 
 include /etc/nginx/mime.types;
 default_type application/octet-stream;
 
 server_names_hash_bucket_size 128;
 
 client_max_body_size 64m;
 
 log_format main '$remote_addr - $remote_user [$time_local] "$request" '
 '$status $body_bytes_sent "$http_referer" '
 '"$http_user_agent" "$http_x_forwarded_for"';
 
 access_log /var/log/nginx/access.log main buffer=16k;
 
 sendfile on;
 tcp_nopush on;
 tcp_nodelay on;
 
 keepalive_timeout 65;
 keepalive_requests 100;
 
 server_tokens on;
 
 # gzip on;
 
 
 
 include /etc/nginx/conf.d/*.conf;
 include /etc/nginx/sites-enabled/*;
 include /var/www/beta.domain.com/current/vhosts/*.conf;

Included Configuration Files

It also loaded the standard configuration files from /etc/nginx/conf.d, /etc/nginx/sites-enabled. However besides that loads config files for (sub)domains that will be attached to projects created by clients using:

include /var/www/beta.domain.com/current/vhosts/*.conf

This location is where the virtual hosts generated by users will be stored.

Enabled Sites

The config file for the current enabled site where we run the app is under:

/etc/nginx/sites-enabled/beta.domain.com.conf

is for the app. Here is the contents of the configuration file:

server {
 
 listen 80 default_server;
 
 #server_name beta.domain.com;
 
 root /var/www/beta.domain.com/current/public;
 
 index index.php index.html index.htm; 
 
 location / {
 try_files $uri $uri/ /index.php$is_args$args;
 }
 
 location ~ \.php$ {
 fastcgi_split_path_info ^(.+\.php)(/.+)$;
 fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
 fastcgi_index index.php;
 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
 include fastcgi_params;
 }
 
 listen 443 ssl; # managed by Certbot
 ssl_certificate /etc/letsencrypt/live/beta.domain.com/fullchain.pem; # managed by Certbot
 ssl_certificate_key /etc/letsencrypt/live/beta.domain.com/privkey.pem; # managed by Certbot
 ssl_session_cache shared:le_nginx_SSL:1m; # managed by Certbot
 ssl_session_timeout 1440m; # managed by Certbot
 
 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # managed by Certbot
 ssl_prefer_server_ciphers on; # managed by Certbot
 
 ssl_ciphers "ECDHE-...."; # managed by Certbot
 
 
 
 if ($scheme != "https") {
 return 301 https://$host$request_uri;
 } # managed by Certbot
 
 }

NB As you can see the server_name has been commented out here. In that case the hostname is used as the server_name. And that is done because of the issues we had using wildcards and Let’s Encrypt with our Laravel configuration.

NBB Also  as we do not use a server_name all subdomains as well as the main domain now seem to load the same and only site which is the beta site where the app runs. This basically makes the hostname the server name as said and to the host the main domain, the beta domain and wildcard domains are connected via DNS records with our hosting provider.

Let’s Encrypt Issues

We run the app on the beta sub domain with a Let’s Encrypt certificate. The issue with it is that they do not accept wildcard domains. Not until next year anyways. That is not ideal of course. And that is why we went for a wildcard certificate with a third party.

New Xolphin SSL Certificates

We decided to purchase a wildcard SSL certificate with another provider, Xolphin. To obtain them we needed to create Certificate Signing Requests for new the SSL certificates with Xolphin or csrs for *.domain.com and domain.com. These needed to be generated under: /etc/ssl/certs/. Before that we had to install openssl with: apt install openssl . Then we were good to run the following command to generate the CSRs using:

openssl req -utf8 -nodes -sha256 -newkey rsa:2048 -keyout domain_com.key -out domain_com.csr

With it we got the public certificate from Xolphin.

CRT Generation

With the CSRs we now were able to generate the missing crts. This we did running the following command.

cat your_domain_name.crt CommodoCA.crt >> bundle.crt

This to concatenate the generated domain name certificate to the Certificate Signing Authority’s certificate.

PEM Generation

And then those crts could be converted to .pem using:

openssl x509 -in input.crt -out input.der -outform DER
openssl x509 -in input.der -inform DER -out output.pem -outform PEM

This is the formatting Let’s Encrypt uses as well. We did not use this formatting however. It is not necessary.

NB Great explanation on SSL files

Wildcard Server Block

So we came up with this wildcard server block for nginx.conf within the https block and after the includes:

server {
    
    #listen 80 default_server; #Was already mentioned for subdomain app setup

    server_name *.domain.com;

    root /var/www/sub.domain.com/current/public;

    index index.php index.html index.htm;

    location / {

	try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {

	fastcgi_split_path_info ^(.+\.php)(/.+)$;
	fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
	fastcgi_index index.php;
	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
	include fastcgi_params;
    }

server {

	listen 443;

	server_name *.site.com;
	ssl On;
	ssl_certificate /etc/ssl/certs/wild_card_domain_com-bundle.crt
	ssl_certificate_key /etc/ssl/certs/wild_card_domain_com.key

	location ~ \.php$ {

		fastcgi_split_path_info ^(.+\.php)(/.+)$;
		fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
		fastcgi_index index.php;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		include fastcgi_params;
	}
}

This worked.

Re-Organization

We however later on decided reorganize things a bit and make it tidier. We moved this wildcard server block to:

/etc/nginx/sites-available/*.domain.com.conf

and symlinked to sites-available from sites-enabled using:

*.domain.com.conf -> /etc/nginx/sites-available/*.domain.com.conf

The block now has:

server {

    listen 80 default_server;

    server_name *.domain.com;

    #return 301 https://$host$request_uri;

    root /var/www/beta.domain.com/current/public;

    index index.php index.html index.htm;

    location / {

        try_files $uri $uri/ /index.php$is_args$args;

    }

    location ~ \.php$ {

        fastcgi_split_path_info ^(.+\.php)(/.+)$;

        fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;

        fastcgi_index index.php;

        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        include fastcgi_params;

    }

    listen 443;

    server_name *.domain.com;

    ssl On;

    ssl_certificate /etc/ssl/certs/wild_card_domain_com-bundle.crt;

    ssl_certificate_key /etc/ssl/certs/wild_card_domain_com.key;

    location ~ \.php$ {

        fastcgi_split_path_info ^(.+\.php)(/.+)$;

        fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;

        fastcgi_index index.php;

        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        include fastcgi_params;

    }

}

Final Tweaks

We will still have to enforce https now of course. We just commented that out as we were doing some Laravel app tweaks. We also need should separate the SSL block from the HTTP block and that will be taken care of and tested as well. If we do get into any issues I will expand this blog post.

 

Tagged in : Tagged in : ,
Jasper Frumau

Jasper has been working with web frameworks and applications such as Laravel, Magento and his favorite CMS WordPress including Roots Trellis and Sage for more than a decade. He helps customers with web design and online marketing. Services provided are web design, ecommerce, SEO, content marketing. When Jasper is not coding, marketing a website, reading about the web or dreaming the internet of things he plays with his son, travels or run a few blocks.