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.