Skip to main content

Magento, Docker & Traefik

This blog post might be outdated!
This blog post was published more than one year ago and might be outdated!
· 4 min read
Stephan Hochdörfer

Besides being big fans of Mark Shust's Docker Configuration for Magento project as I already blogged about, we also love Traefik, the Cloud Native Edge Router. I discovered Traefik years ago and try to use it wherever we can. Depending on the project's goals we either use the open-source version or the enterprise edition. Disclaimer: I am Traefik Ambassador, so I might be a bit biased :)

Since it was clear that we'd use a containerization approach to ship and run the latest Magento project, it meant using Traefik in production as well. In turn that meant to use also use Traefik locally on the development machines to have a consistent set-up in place.

Adding Traefik to Mark Shust's Docker configuration is not so hard. Add the following lines to your docker-compose.yaml file to add Traefik to your local stack:

traefik:
image: traefik:1.7
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./docker/traefik/traefik.toml:/traefik.toml
- ./docker/traefik/domains.pem:/domains.pem
- ./docker/traefik/domains.key.pem:/domains.key.pem

We expose the ports 80 and 443 to serve the Magento sites locally as well as the Trafik Web UI on port 8080 to see the current configuration which helps when debugging things. Besides that, we mount the docker socket from the local machine into the container to that Traefik can listen to the different events when containers go up or down. Additionally, we mount the Traefik configuration file into the container as well as the SSL certificates which more or less looks like this:

defaultEntryPoints = ["https","http"]
logLevel = "ERROR"
debug = true

[web]

[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[[entryPoints.https.tls.certificates]]
certFile = "/domains.pem"
keyFile = "/domains.key.pem"

[docker]
exposedbydefault = false
watch = true

To generate the SSL certificates, I can highly recommend mkcert which allows you to create locally-trusted development certificates. To generate the SSL certificates is a matter of running mkcert like this:

mkcert domain1.loc domain2.loc

If this is the first time you are running mkcert, you should install the local CA in the system trust store to make sure your browser won't complain about insecure SSL certificates. You can do that by running the following command:

mkcert -install

Since the Magento project is using multiple domains that map to different websites in Magento, it was needed to customize the default nginx configuration that is shipped with Mark Shust's setup. The default.conf file looks like this:

# map domains to Magento website identifiers
map $http_host $MAGE_RUN_CODE {
default '';
# local development
domain1.loc website1;
domain2.loc website2;
}

upstream fastcgi_backend {
server unix:/sock/docker.sock;
}

server {
listen 8443;
server_name _; # catch all
set $MAGE_ROOT /var/www/html;
set $MAGE_RUN_TYPE website;

include /var/www/html/nginx[.]conf;
}

First, we need to map the domain names to the website identifiers defined in Magento. This is what happens in the map section above. Second, it was needed to set $MAGE_RUN_TYPE to website to make it clear to Magento that the $MAGE_RUN_CODE represents a website identifier.

Those variables also need be passed to the phpfm process in Magento's default nginx configuration. Besides that it was also needed to pass the HTTPS parameter to phpfpm:

# PHP entry point for main application
location ~ ^/(index|get|static|errors/report|errors/404|errors/503)\.php$ {
try_files $uri =404;
fastcgi_pass fastcgi_backend;
fastcgi_buffers 1024 4k;

fastcgi_read_timeout 600s;
fastcgi_connect_timeout 600s;

fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param MAGE_RUN_CODE $MAGE_RUN_CODE;
fastcgi_param MAGE_RUN_TYPE $MAGE_RUN_TYPE;
fastcgi_param HTTPS $https if_not_empty;
include fastcgi_params;
}

To make Traefik aware of the domains it should handle, all you need is to set a few Traefik labels in the docker-compose.yml configuration file:

app:
image: markoshust/magento-nginx:1.13-8
links:
- db
- phpfpm
volumes: &appvolumes
- ./.git:/var/www/.git
- ~/.composer:/var/www/.composer:delegated
- ./src:/var/www/html
- ./docker/nginx/conf/default.conf:/etc/nginx/conf.d/default.conf
- sockdata:/sock
labels:
- "traefik.enable=true"
- "traefik.backend=app"
- "traefik.protocol=http"
- "traefik.port=8443"
- "traefik.frontend.passHostHeader=true"
- "traefik.frontend.rule=Host:domain1.loc,domain2.loc"

The domains are configured in the traefik.frontend.rule. Since we are still using Traefik 1.7 the syntax is Host:domain1.loc,domain2.loc. Besides that, it is important to set the traefik.frontend.passHostHeader flag to true so that nginx gets the information forwarded which domain is requested and then can do the domain name to website identifier mapping properly.