Docker Community Forums

Share and learn in the Docker community.

Setup local domain and SSL for PHP-apache container

I currently have a simple docker setup in which I’m using PHP:7.3.30-apache and I’m able to view my website at http://localhost:8000.
What is the best way to create a custom domain like “http://local-docker” instead of localhost?
In addition to this I would like to enable SSL certificates for this local domain.

I’ve found a lot of solutions that involve adding a reverse proxy but I’m not sure if this is exactly what I’m looking for.

docker-compose.yml:

version: '3.8'

services:

  php-apache-environment:
    container_name: php-apache
    build:
      dockerfile: ./.docker/php/Dockerfile
    depends_on:
      - db
    volumes:
      - ./public:/var/www/html
    ports:
      - 8000:80

  db:
    container_name: db
    image: mariadb:10.1.48
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: testje
    volumes:
      - db_data:/var/lib/mysql
      - db_conf:/etc/mysql
    ports:
      - "9906:3306"

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    environment:
      PMA_HOST: mariadb
    ports:
        - '8080:80'
    environment:
        PMA_HOST: db
    depends_on:
        - db

# Volumes
volumes:
  db_data:
  db_conf:

Dockerfile:

FROM php:7.3.30-apache
RUN a2enmod rewrite
RUN docker-php-ext-install mysqli && docker-php-ext-enable mysqli && docker-php-ext-install pdo_mysql
RUN apt-get update && apt-get upgrade -y

You are asking for more than one thing:

1 - add a line to your computer’s host file (/etc/hosts for Linux; C:\Windows\System32\drivers\etc\hosts for Windows) pointing the desired name to 127.0.0.1, i.e. adding this hostname to the line starting with 127.0.0.1

127.0.0.1  localhost local-docker

2 - create a certificate + key matching this hostname
To create a self-signed certificate using OpenSSL only for local-docker with an expirationdate 1 year in the future you can use this command

openssl req -x509 -new -out mycert.crt -keyout mycert.key -days 365 -newkey rsa:4096 -sha256 -nodes

and answer the questions to your best knowledge. Important part is the Common Name which has to be the one you have added to your hosts-file above
Example:

Country Name (2 letter code) [AU]:DE
State or Province Name (full name) [Some-State]:Baden-Wuerttemberg
Locality Name (eg, city) []:Pforzheim
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Privat
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:local-docker
Email Address []:

3 - add certificate and enable SSL
add your key mycert.key to image’s directory /etc/ssl/private/
add your certificate mycert.crt to image’s directory /etc/ssl/certs/
You can do so either by ADDing these files to your image during creation within the Dockerfile or mount it later using the docker-compose.yml. I will use the latter option.

Add this commands to your Dockerfile to enable SSL:

a2enmod ssl && a2enmod socache_shmcb

modify /etc/apache2/sites-available/default-ssl.conf to point to your certificate + key so that the lines starting with SSLCertificate... read

SSLCertificateFile      /etc/ssl/certs/mycert.crt
SSLCertificateKeyFile /etc/ssl/private/mycert.key

You can do so by adding these commands to your docker-compose.yml

RUN sed -i '/SSLCertificateFile.*snakeoil\.pem/c\SSLCertificateFile \/etc\/ssl\/certs\/mycert.crt' /etc/apache2/sites-available/default-ssl.conf
RUN sed -i '/SSLCertificateKeyFile.*snakeoil\.key/cSSLCertificateKeyFile /etc/ssl/private/mycert.key\' /etc/apache2/sites-available/default-ssl.conf

Enable the SSL-enabled site with a2ensite default-ssl within your Dockerfile.

4 - Forward a port to container’s SSL-port
add a port of your choice to be forwarded to container’s port 443 to the php-apache-environment-section within your docker-compose.yml so that it reads (using port 8443 for SSL in this example)

  ....
  ports:
    - 8000:80
    - 8443:443
  ....

At the end my Dockerfile looks like this

FROM php:7.4-apache
RUN docker-php-ext-install mysqli && docker-php-ext-enable mysqli && docker-php-ext-install pdo_mysql
RUN a2enmod rewrite && a2enmod ssl && a2enmod socache_shmcb
RUN sed -i '/SSLCertificateFile.*snakeoil\.pem/c\SSLCertificateFile \/etc\/ssl\/certs\/mycert.crt' /etc/apache2/sites-available/default-ssl.conf && sed -i '/SSLCertificateKeyFile.*snakeoil\.key/cSSLCertificateKeyFile /etc/ssl/private/mycert.key\' /etc/apache2/sites-available/default-ssl.conf
RUN a2ensite default-ssl
RUN apt-get update && apt-get upgrade -y

and my docker-compose.yml is this (skipped the MariaDB-part because not needed for this sort-of-tutorial)

version: '3.8'

services:
    php-apache-environment:
        container_name: php-apache
        build: ./
        volumes:
          - ./mycert.crt:/etc/ssl/certs/mycert.crt
          - ./mycert.key:/etc/ssl/private/mycert.key
          - /var/www/html:/var/www/html
        ports:
          - 8000:80
          - 8443:443

Now you should be able to access your Docker-container using https://local-docker:8443 :slight_smile:

Hope this helps or at least point you into the right direction?

1 Like

Thanks for taking your time to respond!
I’m going to try this out later today.

Does the following line enable both localhost and local-docker or does this replace localhost with local-docker?

127.0.0.1  localhost local-docker

I’m asking because I would like to have multiple websites running simultaneously in different docker containers.

Would the following line work for this purpose?

127.0.0.1  localhost local-docker local-anothersite local-anothersite2

I’m also a little confused that there is no configuration needed to point the server to the new domain other than the SSL certificate.
What if I wanted to use a custom local domain without SSL?

Hello,

editing the hosts-file is similar to setting some DNS-entries but only visible to your local computer.
So: Yes, you can add as many entries to one IP-address as you want to have.
And: This has nothing to do with SSL or not-SSL - you still can decide to access a port with http and another one with https.

Right now you can access every container with every hostname as your computer only decides which container to access based on the destination-TCP-port.
The SSL-certificate is only used like a passport presented by the webserver/container to your browser to check/ensure you are still talking to the correct host.

For the future you can do more advanced stuff - using a loadbalancer (like traefik) listening on one port :443 and decides where (which webserver/container) to send the request to based on the requested hostname.
Also you can create your own CA (certificate authority) and/or using certificates with SAN (subject alternate name = certficate is valid for multiple hostnames/ip-addresses/domains)