PHP / Magento Dev Blog

  • Home

Local HTTPS with mkcert and nginx-proxy – end browser warnings

by Henryk Tews / Saturday, 24 October 2026 / Published in Środowiska

Working on HTTP locally has one persistent problem: application behaviour differs from production for everything HTTPS-dependent – Secure cookies, mixed content, HSTS, OAuth redirects. Mkcert generates locally trusted certificates without a CA, nginx-proxy automatically routes domains to containers. Together they give you an environment that looks like production.

mkcert – trusted CA in one command

# Install mkcert
# macOS
brew install mkcert
brew install nss  # for Firefox

# Linux (Debian/Ubuntu)
sudo apt install libnss3-tools
curl -Lo mkcert https://dl.filippo.io/mkcert/latest?for=linux/amd64
chmod +x mkcert && sudo mv mkcert /usr/local/bin/

# Install local CA in trusted certificate stores
mkcert -install
# Installs in: system store, Firefox, Chrome/Chromium, Java

# Generate certificate for local domain
mkcert myshop.local "*.myshop.local" localhost 127.0.0.1

# Creates:
# myshop.local+3.pem      - certificate
# myshop.local+3-key.pem  - private key

nginx-proxy – automatic routing via Docker labels

# docker-compose.proxy.yml - run once, works for all projects
version: '3.8'

services:
  nginx-proxy:
    image: nginxproxy/nginx-proxy:latest
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./certs:/etc/nginx/certs:ro
      - ./vhost.d:/etc/nginx/vhost.d:ro
      - ./html:/usr/share/nginx/html
    restart: unless-stopped

networks:
  default:
    name: nginx-proxy
    external: true
# Create nginx-proxy network
docker network create nginx-proxy

# Copy mkcert certificates to certs directory
# nginx-proxy looks for: domain.crt and domain.key
cp myshop.local+3.pem     certs/myshop.local.crt
cp myshop.local+3-key.pem certs/myshop.local.key

# Start proxy
docker compose -f docker-compose.proxy.yml up -d

Project docker-compose with nginx-proxy

# docker-compose.yml - Magento/PHP project
version: '3.8'

services:
  nginx:
    image: nginx:alpine
    container_name: myshop-nginx
    volumes:
      - ./src:/var/www/html:ro
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
    environment:
      - VIRTUAL_HOST=myshop.local       # nginx-proxy reads this
      - VIRTUAL_PORT=80
      - HTTPS_METHOD=redirect           # automatic HTTP to HTTPS redirect
    networks:
      - nginx-proxy
      - internal

  php:
    build: ./docker/php
    container_name: myshop-php
    volumes:
      - ./src:/var/www/html
    networks:
      - internal

  db:
    image: mariadb:10.6
    container_name: myshop-db
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: magento
    networks:
      - internal

networks:
  nginx-proxy:
    external: true
  internal:
    driver: bridge

Verification and debugging

# Check if nginx-proxy sees the containers
docker logs nginx-proxy | grep -i "myshop"

# Check generated nginx config
docker exec nginx-proxy cat /etc/nginx/conf.d/default.conf

# Test certificate
curl -v https://myshop.local/ 2>&1 | grep -E "subject|issuer|SSL"
# Should show: issuer: O=mkcert development CA

# Add domain to /etc/hosts if not using DNS
echo "127.0.0.1 myshop.local" | sudo tee -a /etc/hosts

DDEV with mkcert

DDEV since version 1.21 configures mkcert automatically during ddev start – if mkcert is installed, DDEV generates the certificate and registers the CA. Nothing manual needed. The nginx-proxy approach above is for projects without DDEV or when you need a single proxy for multiple different stacks (PHP, Node, Python) running simultaneously.

Certificates are valid for 825 days (the browser-imposed limit for trusted CA certificates). A renewal cron: mkcert -install && mkcert *.myshop.local myshop.local && cp ... – sufficient once every two years.

About Henryk Tews

© 2026 Created by

TOP
Zarządzaj zgodą
Aby zapewnić jak najlepsze wrażenia, korzystamy z technologii, takich jak pliki cookie, do przechowywania i/lub uzyskiwania dostępu do informacji o urządzeniu. Zgoda na te technologie pozwoli nam przetwarzać dane, takie jak zachowanie podczas przeglądania lub unikalne identyfikatory na tej stronie. Brak wyrażenia zgody lub wycofanie zgody może niekorzystnie wpłynąć na niektóre cechy i funkcje.
Funkcjonalne Always active
Przechowywanie lub dostęp do danych technicznych jest ściśle konieczny do uzasadnionego celu umożliwienia korzystania z konkretnej usługi wyraźnie żądanej przez subskrybenta lub użytkownika, lub wyłącznie w celu przeprowadzenia transmisji komunikatu przez sieć łączności elektronicznej.
Preferencje
Przechowywanie lub dostęp techniczny jest niezbędny do uzasadnionego celu przechowywania preferencji, o które nie prosi subskrybent lub użytkownik.
Statystyka
Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do celów statystycznych. Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do anonimowych celów statystycznych. Bez wezwania do sądu, dobrowolnego podporządkowania się dostawcy usług internetowych lub dodatkowych zapisów od strony trzeciej, informacje przechowywane lub pobierane wyłącznie w tym celu zwykle nie mogą być wykorzystywane do identyfikacji użytkownika.
Marketing
Przechowywanie lub dostęp techniczny jest wymagany do tworzenia profili użytkowników w celu wysyłania reklam lub śledzenia użytkownika na stronie internetowej lub na kilku stronach internetowych w podobnych celach marketingowych.
  • Manage options
  • Manage services
  • Manage {vendor_count} vendors
  • Read more about these purposes
Zobacz preferencje
  • {title}
  • {title}
  • {title}