Local Development with Self Signed Certificate

To have Local Development with Self Signed Certificate has been a pain in the last two years. Chrome and other browsers have been making it harder and harder. Well there still is a way to do this and here I will let you know how.

Inspiration

To realize a self signed certificate that would be accepted by all browsers I failed many times in the past. Until I bumped into a great to follow post by Thijs Busser. He explains all well in a great post .  He even explains final steps for Windows and Mac users. I was only interested in the MacOS part of things. So here is the gist of things.

Root Certificate

The thing I had been missing all along was the need for a root certificate. This you need to generate your self signed certificate and this is the only one you need to add and get accepted by MacOS in the Keychain. So let’s tag along here.

The following commands are needed to create a root certificate:

openssl genrsa -des3 -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024  -out rootCA.pem

SSL Certificate

Once you have your root certificate you can work on the actual SSL certificate. You can do this as follows:

The following commands are needed to create an SSL certificate issued by the self created root certificate:

openssl req -new -nodes -out server.csr -newkey rsa:2048 -keyout server.key
openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 500 -sha256 -extfile v3.ext

V3 Extension

The final command does need to read data from v3.ext. This contains some necessary details including the alternate names for your local website.

The referenced v3.ext file should look something like this:

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = acme-site.dev
DNS.2 = acme-static.dev

You of course need to use your local domains like laravel.test and or *.laravel.test for example.

Nginx Certs Loading

To use these certificates you need to refer to them in your Nginx conf.  Did it like so in a Laradock setup:

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    listen 443 default_server ssl http2;
    listen [::]:443 default_server ssl http2;
    ssl_certificate /etc/nginx/ssl/server.crt;
    ssl_certificate_key /etc/nginx/ssl/server.key;

    root /var/www/public;
    index index.php index.html index.htm;

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

    location ~ \.php$ {
        try_files $uri /index.php =404;
        fastcgi_pass php-upstream;
        fastcgi_index index.php;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        #fixes timeouts
        fastcgi_connect_timeout 60;
        fastcgi_read_timeout 1200;
        fastcgi_send_timeout 360;
        client_max_body_size 500M;
        # fastcgi_intercept_errors on; 
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }

    location /.well-known/acme-challenge/ {
        root /var/www/letsencrypt/;
        log_not_found off;
    }

    error_log /var/log/nginx/laravel_error.log;
    access_log /var/log/nginx/laravel_access.log;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name laravel.test;
    root /var/www/public;

    ssl_certificate /etc/nginx/ssl/server.crt;
    ssl_certificate_key /etc/nginx/ssl/server.key;

    index index.php index.html index.htm;

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

    location ~ \.php$ {
        try_files $uri /index.php =404;
        fastcgi_pass php-upstream;
        fastcgi_index index.php;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        #fixes timeouts
        fastcgi_connect_timeout 60;
        fastcgi_read_timeout 1200;
        fastcgi_send_timeout 360;
        client_max_body_size 500M;
        # fastcgi_intercept_errors on; 
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }

    location /.well-known/acme-challenge/ {
        root /var/www/letsencrypt/;
        log_not_found off;
    }

    error_log /var/log/nginx/laravel_error.log;
    access_log /var/log/nginx/laravel_access.log;
}

Worked like a charm with certificates in place.

Root Certificate Keychain Addition

Once this is done you do need to add the root certificate to your keychain and have it accepted.

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.