Deploy WordPress with Docker, Traefik, and CrowdSec for Enhanced Security – Part 2

To continue installing WordPress on Docker Securely, we need to tackle the next component. With Docker installed and ready to go, the next step in our deployment process is setting up Traefik as our dynamic reverse proxy and load balancer. Traefik will manage the routing of incoming traffic to our WordPress containers, handle SSL termination to ensure secure communication and provide seamless scalability. In this section, we’ll guide you through configuring and deploying Traefik in your Docker environment, ensuring that it efficiently and securely directs traffic to your WordPress instances.


Configuring Traefik

The commands below set up the necessary directory structure and configuration files for deploying Traefik. The data subdirectory holds 3 main files to configure Traefik, acme.json will dynamically store the SSL certs, traefik.yml, is the main configuration file for redirection services and for obtaining SSL certificates, and config.yml for any additional configurations.

mkdir traefik
cd traefik
mkdir data
cd data
touch acme.json
chmod 600 acme.json
touch traefik.yml
touch config.yml

Create a docker network named proxy to contain the stack of containers:

docker network create proxy

Back out of the data directory to the main traefik directory. Now you will create your docker-compose.yml file that will deploy the Traefik container.

nano docker-compose.yml

Here is an example of what to put in your docker-compose.yml file. Starting with services, you will identify your Traefik image. I used the latest version of 3.0 available. I used traefik:latest previously but it pulled version 2.x so I specified 3.0.0 directly.
The parts you want to focus on are the name of your container, the environment section, and the labels section.

services:
  traefik:
    image: traefik:3.0.0
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    ports:
      - 80:80
      - 443:443
    environment:
      - CF_DNS_API_TOKEN=YOUR_API_TOKEN
      # If you choose to use an API Key instead of a Token, specify your email as well
      # - [email protected]
      # - CF_API_KEY=YOUR_API_KEY
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /home/username/traefik/data/traefik.yml:/traefik.yml:ro
      - /home/username/traefik/data/acme.json:/acme.json
      - /home/username/traefik/data/config.yml:/config.yml:ro
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=http"
      - "traefik.http.routers.traefik.rule=Host(`traefik-dashboard.example.com`)"
      - "traefik.http.middlewares.traefik-auth.basicauth.users=USER:BASIC_AUTH_PASSWORD"
      - "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
      - "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
      - "traefik.http.routers.traefik-secure.entrypoints=https"
      - "traefik.http.routers.traefik-secure.rule=Host(`traefik-dashboard.example.com`)"
      - "traefik.http.routers.traefik-secure.middlewares=traefik-auth"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.tls.certresolver=cloudflare"
      - "traefik.http.routers.traefik-secure.tls.domains[0].main=example.com"
      - "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.example.com"
      - "traefik.http.routers.traefik-secure.service=api@internal"

networks:
  proxy:
    external: true

To obtain SSL certificates from Let’s Encrypt, you will need to verify that you own the domain name(s) that you plan to use for your WordPress site. To verify ownership, you can use DNS Validation. I use CloudFlare in this example. If you don’t use CloudFlare, you will need to research the DNS service you use. Under the environment section, you will need to enter your API token from CloudFlare.
Let’s get a new token from Cloudflare.

Navigate to your domain name and choose Get API Token. Then choose Create Token.

Choose Edit zone DNS template. This will allow Traefik to read the DNS information via the API.

Set the permissions to Zone -> DNS -> Read. Set the Zone Resources Include -> Specific zone -> your domain. Set any IP filtering you may want and finally set a TTL if you wish.

Finally, copy all the Token information to a secure place to be used in your Traefik configuration.

Now, let’s take a look and the Labels section in our docker-compose.yml file. The Labels section in Docker provides a way to add metadata to containers, which Traefik can use to configure routing rules, middleware, and SSL settings dynamically. Here’s a detailed breakdown of each label in the provided example:

Enable Traefik. This label tells Traefik to manage this container. Without this label, Traefik will ignore the container entirely.

- "traefik.enable=true"
...

These labels define an HTTP router named traefik:

  • EntryPoint: Specifies that this router listens on the http entrypoint.
  • Rule: Uses a host rule to route traffic to traefik-dashboard.example.com.
...
- "traefik.http.routers.traefik.entrypoints=http"
- "traefik.http.routers.traefik.rule=Host(`traefik-dashboard.example.com`)"
...

This sets up a basic authentication middleware named traefik-auth:

  • BasicAuth: Protects the route with a username (USER) and a base64-encoded password (BASIC_AUTH_PASSWORD).

To create an encoded password, check out this post from dev.to – Basic HTTP authentication in Traefik 2

...
- "traefik.http.middlewares.traefik-auth.basicauth.users=USER:BASIC_AUTH_PASSWORD"
...

These labels create a middleware to enforce HTTPS:

  • RedirectScheme: Redirects HTTP traffic to HTTPS.
  • Headers: Sets the X-Forwarded-Proto header to https to indicate that the request was forwarded using HTTPS.
...
- "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
- "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
...

This label attaches the HTTPS redirect middleware to the HTTP router.

...
- "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
...

These labels define a secure HTTPS router named traefik-secure:

  • EntryPoint: Specifies that this router listens on the https entrypoint.
  • Rule: Routes traffic to traefik-dashboard.local.example.com.
  • Middleware: Applies the traefik-auth middleware for basic authentication.
  • TLS: Enables TLS for this router.
  • CertResolver: Uses the cloudflare resolver to obtain SSL certificates.
  • Domains: Specifies the primary domain (local.example.com) and a wildcard domain (*.local.example.com) for the certificates.
...
- "traefik.http.routers.traefik-secure.entrypoints=https"
- "traefik.http.routers.traefik-secure.rule=Host(`traefik-dashboard.example.com`)"
- "traefik.http.routers.traefik-secure.middlewares=traefik-auth"
- "traefik.http.routers.traefik-secure.tls=true"
- "traefik.http.routers.traefik-secure.tls.certresolver=cloudflare"
- "traefik.http.routers.traefik-secure.tls.domains[0].main=example.com"
- "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.example.com"
...

Finally, this label points the secure router to the Traefik internal API service, enabling access to the Traefik dashboard and API.

...
- "traefik.http.routers.traefik-secure.service=api@internal"

To finish up our docker-compose.yml file, we need to define the network that Traefik will be attached to.

networks:
  proxy:
    external: true

Creating the traefik.yml File

The traefik.yml file configures a Traefik reverse proxy, defining its entry points (ports), providers (e.g., Docker, file), and middleware. It sets up routing rules, SSL certificates, and logging preferences. This file essentially tells Traefik how to handle incoming traffic, manage services, and route requests to the appropriate backend services, ensuring secure and efficient load balancing and traffic management for your applications.

Here is a standard configuration. Note that the 2 other files, config.yml, and acme.json are referenced here. Also, if you are using another DNS service other than Cloudflare, you will need to change the certificatesResolvers section to suit your service provider.

api:
  dashboard: true
  debug: true
entryPoints:
  http:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: https
          scheme: https
  https:
    address: ":443"
serversTransport:
  insecureSkipVerify: true
providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
  file:
    filename: /config.yml
certificatesResolvers:
  cloudflare:
    acme:
      email: [email protected]
      storage: acme.json
      dnsChallenge:
        provider: cloudflare
        #disablePropagationCheck: true # uncomment this if you have issues pulling certificates through cloudflare, By setting this flag to true disables the need to wait for the propagation of the TXT record to all authoritative name servers.
        #delayBeforeCheck: 60s # uncomment along with disablePropagationCheck if needed to ensure the TXT record is ready before verification is attempted 
        resolvers:
          - "1.1.1.1:53"
          - "1.0.0.1:53"

Let’s fire up the Traefik container.

docker-compose up -d

Make sure your internal DNS is pointing traefik-dashboard.example.com to your docker host. If all things are running correctly, you should see the dashboard.

After installing Docker and Traefik, the next step is to set up the WordPress stack. Check out part 3 of this series to deploy WordPress on Docker securely.

If you missed part 1 of this series go to Deploy WordPress with Docker, Traefik, and CrowdSec for Enhanced Security – Part 1

Leave a Comment

Your email address will not be published. Required fields are marked *