It's fairly straightforward to get mkcert working in a third-party container. Getting it working with headless Chrome, Chromium, Firefox, and other browsers that don't use the system store in Linux is a little less intuitive.
First, let's look at the changes we have to make to get everything to work. I'm including brief explanations under each file where necessary. I will explain them together at the end.
.ddev/docker-compose.chrome.yaml
:
---
version: '3.6'
services:
chrome:
build:
context: ./chrome-build
restart: unless-stopped
container_name: ddev-${DDEV_SITENAME}-chrome
labels:
com.ddev.site-name: ${DDEV_SITENAME}
com.ddev.approot: $DDEV_APPROOT
volumes:
- ddev-global-cache:/mnt/ddev-global-cache
external_links:
- "ddev-router:fps.ddev.local"
- "ddev-router:dev.fillpdf-service.com"
cap_add:
- SYS_ADMIN
ports:
- '9222:9222'
networks:
default:
external:
name: ddev_default
We changed the image
option to build
, and we are pointing it a new folder we're about to create.
New folder: .ddev/chrome-build/Dockerfile
.ddev/chrome-build/Dockerfile
FROM justinribeiro/chrome-headless
ADD chrome-startup.sh /
ENV MKCERT_VERSION=v1.3.0
USER root
RUN apt-get update && apt-get install -y curl openssl libnss3-tools && curl -sSL https://github.com/FiloSottile/mkcert/releases/download/$MKCERT_VERSION/mkcert-$MKCERT_VERSION-linux-amd64 -o /usr/local/bin/mkcert && chmod +x /usr/local/bin/mkcert && apt-get purge -y curl && apt-get clean && chmod +x /chrome-startup.sh
ENTRYPOINT [ "/chrome-startup.sh" ]
.ddev/chrome-build/chrome-startup.sh
#!/bin/bash
if [[ ! -f /.mkcert-configured ]]; then
#!/usr/bin/env bash
# Install for root (system).
CAROOT="/mnt/ddev-global-cache/mkcert" mkcert -install
# Install for user: chrome.
su chrome -c 'mkdir -p $HOME/.local/share/mkcert'
cp -R /mnt/ddev-global-cache/mkcert/* /home/chrome/.local/share/mkcert/
chown -R chrome: /home/chrome/.local/share/mkcert
# Create the NSS trust store BEFORE running mkcert; mkcert doesn't reliably
# work otherwise.
su chrome -c 'mkdir -p $HOME/.pki/nssdb'
su chrome -c 'certutil -d sql:$HOME/.pki/nssdb -N --empty-password'
su chrome -c 'cd $HOME && TRUST_STORES=nss mkcert -install'
touch /.mkcert-configured
fi
# Run headless Chrome in the foreground (the original container's command).
su chrome -c 'google-chrome --headless --disable-gpu --remote-debugging-address=0.0.0.0 --remote-debugging-port=9222'
The Dockerfile builds a custom container on top of justinribeiro/chrome-headless
. We install the mkcert prerequisites, mkcert itself, and the optional libnss3-tools
prerequisite. It's not optional for us in this case.
We also change the user context to root
because we need to be root for the startup script to work.
The chrome-startup.sh script installs mkcert. We have to install it at startup because we rely on the mounted volume containing the certificates. It is not available at build time. It installs it system-wide and then installs it for the chrome
user, which headless Chrome actually runs as in this container.
One notable tricky part when installing for the chrome
user is that we have to manually create the NSS DB that Firefox, headless Chrome, and Chromium use. The mkcert -install
command is supposed to create this automatically, but it doesn't always. It does, however, consistently work if we create the NSS DB first.
After adding these files, simply use ddev start
or ddev restart
, configure Behat to use the headless Chrome on http://192.168.65.2:9222
, and you should now be able to set your Behat\MinkExtension
.base_url
to https://mysite.ddev.local
(where mysite
is replaced with your project name). Headless Chrome should accept the SSL certificate now. I have not explained Behat configuration in great detail, as it's out of the scope of this answer.
Behat should now work (or continue working).
You can also test if headless Chrome recognizes your SSL certificate manually.
SSH into the container: ddev ssh -s chrome
Print the content of the website: su chrome -c 'google-chrome --headless --disable-gpu --dump-dom https://mysite.ddev.local'
If certificate validation failed, you'll see output containing this:
[0524/160648.082825:ERROR:cert_verify_proc_nss.cc(975)] CERT_PKIXVerifyCert for dev.fillpdf-service.com failed err=-8179
If you instead see a bunch of HTML, that means it's working!