DEV Community

Vishal Raj
Vishal Raj

Posted on • Edited on

Using HTTPS in docker for local development

As a web application developer, one of the most common challenge faced is, not having the local development environment close enough to the production environment. While there can be many aspects to this, in this post we will focus on the following two

  • Having a domain name, instead of something like http://localhost:8080
  • Having a valid HTTPS certificate on the local development machine

Also, I am going to use docker for this demonstration. So lets begin.

I am going to use Wordpress as my example application. So lets head over to the docker page for Wordpress. Scrolling to the bottom shows us a sample configuration which can be used with docker-compose to have Wordpress running with MySQL.

Open a terminal and make a folder with name, say wordpress-with-https and move inside it. Now create a file with name docker-compose.yml and paste the contents copied from here.

version: '3.9'

services:
  wordpress:
    image: wordpress
    restart: always
    ports:
      - 8080:80
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: exampleuser
      WORDPRESS_DB_PASSWORD: examplepass
      WORDPRESS_DB_NAME: exampledb
    volumes:
      - wordpress:/var/www/html
  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: exampledb
      MYSQL_USER: exampleuser
      MYSQL_PASSWORD: examplepass
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - db:/var/lib/mysql

volumes:
  wordpress:
  db:
Enter fullscreen mode Exit fullscreen mode

Save and exit from the file. Now lets start the docker containers - docker-compose up. This will fire up the Wordpress and MySQL containers with appropriate configuration. Open a browser and type the URL - http://localhost:8080 and press enter. At this point, we can see that we have now successfully opened up the Wordpress setup page.

In order to access the Wordpress app over domain name, we need to make an entry in the /etc/hosts files and add the following at the end of the file - 127.0.0.1 my-wordpress-blog.local. After this, now we should be able to access - http://my-wordpress-blog.local:8080 in browser.

In order to have HTTPS in the local development environment, we will use a utility called mkcert. In order to have mkcert, we first need to install the dependency - libnss3-tools. Open a terminal and run - sudo apt install libnss3-tools -y. Now lets download the pre-built mkcert binary from the github releases page. Download the appropriate binary. Since I am using Ubuntu on my develoment machine, so I will use mkcert-v1.4.3-linux-amd64. Download the binary file and move it to /usr/local/bin. We also need to make the file executable - chmod +x mkcert-v1.4.3-linux-amd64. Now lets create a softlink with name - mkcert - ln -s mkcert-v1.4.3-linux-amd64 mkcert. The first step is to become a valid Certificate Authority for local machine - mkcert -install. This will install the root CA for local machine.

Now lets get back to generating self-signed SSL certificates. Lets move back to our development folder wordpress-with-https. Here we will create directory proxy and inside it certs and conf. Lets move inside proxy/certs and generate the certificates.

vishalr@ubuntu ~/wordpress-with-https> mkcert \
>  -cert-file my-wordpress-blog.local.crt \
>  -key-file my-wordpress-blog.local.key \
>  my-wordpress-blog.local

Created a new certificate valid for the following names
 - "my-wordpress-blog.local"

The certiciate is at my-wordpress-blog.local.crt and the key at "my-wordpress-blog.local.key"

It will expire on 14 August 2021

vishalr@ubuntu ~/wordpress-with-https>
Enter fullscreen mode Exit fullscreen mode

This will generate the SSL key and certificate file which is valid for domain - my-wordpress-blog.local. Now lets modify the contents of file docker-compose.yml to use nginx as the proxy. Add the following contents under services tag.

services:
  proxy:
    image: nginx:1.19.10-alpine
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./proxy/conf/nginx.conf:/etc/nginx/nginx.conf
      - ./proxy/certs:/etc/nginx/certs
    depends_on:
      - wordpress
Enter fullscreen mode Exit fullscreen mode

Now lets focus on the nginx configuration to use it as proxy. Edit the file wordpress-with-https/proxy/conf/nginx.conf and add the following configuration.

events {
  worker_connections 1024;
}

http {
  server {
    listen 80;
    server_name my-wordpress-blog.local;
    return 301 https://$host$request_uri;
  }

  server {
    listen 443 ssl;
    server_name my-wordpress-blog.local;

    ssl_certificate /etc/nginx/certs/my-wordpress-blog.local.crt;
    ssl_certificate_key /etc/nginx/certs/my-wordpress-blog.local.key;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
      proxy_buffering off;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Forwarded-Host $host;
      proxy_set_header X-Forwarded-Port $server_port;

      proxy_pass http://wordpress;
    }
}
Enter fullscreen mode Exit fullscreen mode

If the docker containers are still running, press Ctrl + C to stop them. Now lets fire up the docker containers with the updated contents in docker-compose.yml. If all has been done correctly, we should have everything ready. Now lets open the browser and enter the url - http://my-wordpress-blog.local. This should redirect to https://my-wordpress-blog.local. Now if you look at the top left of the browser, the lock icon is green, which means that the browser has accepted our locally generated self signed ssl certificates.

The github repository can be found here

NOTE: mkcert can be use to generate ssl certificates for local development only.

Top comments (13)

Collapse
 
rubendob profile image
rubendob

Ey men

thanks for your tutorial. Was useful to me cause I want to test Wordpress API Rest locally with some Python code and I think HTTPS is mandatory to that scenario so kudos on that.

I have to debug just a little cause I have 502 from proxy but I was able to fix it.

Regards

Collapse
 
rpino profile image
Rafael

Hi, how did you fix it?

Collapse
 
altela profile image
Altela Eleviansyah Pramardhika

working amazingly well, thanks

In case someone is having error during docker-compose up after configuring nginx, try to open the nginx.conf and add } (closing curly braces) at the end.

Also, let the ssl_certificate and ssl_certificate_key path in nginx.conf file as it is. It is actually path of nginx.conf inside the docker. You just need to put the .crt and .key inside certs folder

Collapse
 
gorynych profile image
Stepan Mozyra

Install something locally to be able to play with docker? ))) C'mon

Collapse
 
vishalraj82 profile image
Vishal Raj

Well, its only facilitating the development. Dont' you install docker as well?

Collapse
 
gorynych profile image
Stepan Mozyra

Yeah... I'm also install OS on my machine before installing Docker, and all of these are installed on top of hardware manufacturer's BIOS, installed on motherboard chips )). But I really hope you understand the difference ;)

Thread Thread
 
raymondpeterfellow profile image
Seb

💩

Collapse
 
alastairmeasures profile image
Alastair Measures

Thank you - great article.

Good to see Alpine being used.

Will definitely reread the SSL section.

Collapse
 
sebastian_fehlandt profile image
Sebastián Fehlandt

Hi

Thank you for this. I did it and it works but the static files are being served in the url of the docker-service. E.g:

wordpress/wp-admin/css/install.min...

Which of course is not reachable since port 80 is assigned to the proxy service.

Did you have this problem? How can it be fixed?

Collapse
 
pjaws profile image
Paul Matthew Jaworski

Can you explain the proxy_pass line? I'm a little confused about what the upstream is supposed to be there for non-Wordpress apps.

Collapse
 
pjaws profile image
Paul Matthew Jaworski

Figured it out. Looks like it just needs to be the name of the app service.

Collapse
 
stalukder03 profile image
Sajib Talukder

It did not work for me, OS is Ubuntu. Could you please help to get rid of this issue?

Image description

Collapse
 
ooosys profile image
oOosys • Edited

Have you checked the connection? Have you checked the proxy and the firewall? Have you checked if hello.test is equipped with all it needs?
Try to ask the same on stackoverflow to see why your question is not detailed enough to be a good question there (e.g. you haven't provided the code and full details, so that others can reproduce your problem).