Lockdown WordPress with Traefik proxy – No plugins
TL;DR – See solution in docker compose
I once had a server that was hacked on a DigitalOcean VPS. Having my server hacked was my goal at the time – yeah, just hear me out.
The intention was to understand what happens to a server after it’s been compromized. Purely from an investigative and learning standpoint because it was the first time I had a service publicly exposed. The server ran for about 4 months… nothing. Until I got a notification that Google Chrome was blocking my website due to malicious behavior. I was excited.
I quickly logged in to my server to see if I can piece together what the hacker is using my server for. After looking through some of the config files, I saw blocks of indecipherable PHP code that appeared to be base64 encoded. So I attempted to decode the blocks (it was base64), but they used random variable names that made it difficult to understand what was being done. I got a clearer picture by monitoring incomming requests in nginx to see what was being sent to the server – they were payloads to redirect the user to other websites. Ultimately, they had repurposed my server to be a proxy for an email spam/phishing attack. Requests came from random locations, but there was indication that it originated from user’s email accounts. File modified was primarily
This post will cover how Traefik can be used to lockdown your wordpress installation. If you have managed a wordpress server, you know that your site gets attacked several thousand times a day. I will go over a few types of attacks and how to mitigate them by using a Traefik proxy in front of your wordpress server.
- You are an admin on your wordpress server
- You are able to run Traefik either as a docker container or stand alone service
- You have installed and configured
docker-composeand the apache benchmark tool
Docker compose configuration
Although this post is wordpress specific, the same techniques can be applied to any web service behind a Traefik proxy
For the purpose of condensing all parts of this infrastructure into something easy to deploy and test, I will be using docker compse to encapsulate all the configuration required. Note that this is not a production setup as there are considerations in terms of resilience, security and data persistence that are not accounted for in this docker compose setup – that’s beyond the scope of this post.
The following is a summary of what is being done in the docker-compose file above:
- Run a
wordpressserver with a
- Run a
Traefikserver that recieves all incomming requests, then routes to the wordpress server
Traefikusing labels on the containers
- Setup rate limiting – 10 requests per second with an allowed burst of 50 requests per second.
- Add basic auth to any request with any of these prefixes:
username: test, password: password
- Setup entrypoints where Traefik will listen for requests
- Enable Traefik dashboard on port
- Enable access logging
Docker Compose – See it in action
version: '3.1' services: db: image: mysql:5.7 restart: always environment: MYSQL_DATABASE: exampledb MYSQL_USER: exampleuser MYSQL_PASSWORD: examplepass MYSQL_RANDOM_ROOT_PASSWORD: '1' volumes: - db:/var/lib/mysql wordpress: image: wordpress restart: always environment: PORT: 80 WORDPRESS_DB_HOST: db WORDPRESS_DB_USER: exampleuser WORDPRESS_DB_PASSWORD: examplepass WORDPRESS_DB_NAME: exampledb volumes: - wordpress:/var/www/html labels: - "traefik.enable=true" - "traefik.http.middlewares.auth-users.basicauth.users=test:$apr1$gkhQMADi$rQ3MBaI0Zbj6p.y62OsIJ." - "traefik.http.middlewares.known-ips.ipwhitelist.sourceRange=192.168.1.7,127.0.0.1/32,0.0.0.0/0" - "traefik.http.middlewares.wp-ratelimit.ratelimit.average=10" - "traefik.http.middlewares.wp-ratelimit.ratelimit.burst=50" - "traefik.http.middlewares.secured.chain.middlewares=known-ips,auth-users,wp-ratelimit" - "traefik.http.routers.wp_admin.entrypoints=web" - "traefik.http.routers.wp_admin.middlewares=secured" - "traefik.http.routers.wp_admin.rule=PathPrefix(`/wp-admin`,`/admin`,`/wp-login.php`) || Method(`POST`)" - "traefik.http.routers.wp_web.entrypoints=web" - "traefik.http.routers.wp_web.middlewares=wp-ratelimit" - "traefik.http.routers.wp_web.rule=Host(`localhost`)" traefik: image: "traefik:v2.2.1" container_name: "traefik" command: # - "--log.level=DEBUG" - "--accesslog=true" - "--api.insecure=true" - "--api.dashboard=true" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:8080" - "--entrypoints.traefik.address=:8888" labels: traefik.enable: true traefik.http.routers.traefik.service: api@internal traefik.http.routers.traefik.entrypoints: traefik ports: - "8080:8080" - "8888:8888" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" volumes: wordpress: db:
- View traefik logs:
docker logs -f --tail 10 traefik
- Send 1000 requests from 10 concurrent http clients:
ab -n 1000 -c 10 http://localhost:8080/
- Navigate to
http://localhost:8080/wp-admin– You will be prompted with a basic auth prompt. Enter username: test, password: password to authenticate.
Traefik is an open-source Edge Router that makes publishing your services a fun and easy experience. It receives requests on behalf of your system and finds out which components are responsible for handling them.
What sets Traefik apart, besides its many features, is that it automatically discovers the right configuration for your services. The magic happens when Traefik inspects your infrastructure, where it finds relevant information and discovers which service serves which request.
Traefik has native support for docker and routes can be auto configured by defining docker labels that are used to configure Traefik – more on this later.
Read more about Traefik here…
Common WordPress attacks
When dealing with securing any system, it’s usually an excersise in limiting the attack surface of your system. This means limiting the points of penetration exposed to attackers, then securing those entry points. I’ll assume that your server only exposes endponts that absolutely need to be open – like port 22 (ssh) and http ports (80, 443).
WordPress specific attacks target vulnerabilities in PHP, wordpress plugins, compromized wordpress themes, outdated wordpress installations, poorly secured servers with easy to guess ssh username and password, poorly secured FTP servers or even exposed mysql server. Most of these attacks involve sending requests to
Traefik is used to mitgate the following types of attacks:
- Brute force wordpress login attempts
- WordPress admin probes
- Denial of service
These forms of attack are blocked using the following features in Traefik
- Basic auth – serves as 2nd form of authentication
- IP source filtering – You can limit what IP addresses can reach certain endpoints, like
- Rate limiting – Limit abusive requests. a
429 response codeis sent when the user exceeds the defined limit.
Obviously this is just one part of locking down your server infrastructure. Observability is a key part of security in order to understand what is happening in your environment. I cannot stress how important it is to have a way to observe your infrastructure. I don’t care what you use, just observe your infrastructure. At least you will need the following:
- Logging system – collect access logs from your webserver
- Metrics system – Collect metrics from Traefik and other parts of your infastructure and view time series data from your services. Traefik exposes a Prometheus endpoint.
- Alerting system – A mechanism to alert you when anomalies are detected
That said, Traefik is an excellent piece of software. Very modern, forward thinking with great features to help secure your infrastructure. It has support for service discovery from consul, docker, kubernetes. Traefik will also automatically manage Let’s Encrypt certificates for your services.
Simple to use software is hard, so I appreciate what the Traefik team have built.