Running the traffic reverse proxy led to some issues with iFrames. Further there were issues due to depreciated settings in configuration..yml. There I have updated the configurations as follows
traefik docker-compose.yml
version: "3.3"
services:
traefik5:
image: "traefik:2.10.3"
container_name: "traefik5"
restart: "always"
command:
- "--global.sendAnonymousUsage"
#- "--log.level=DEBUG"
- "--log.filePath=/var/log/traefik.log"
- "--accesslog=true"
- "--accesslog.filePath=/var/log/access.log"
- "--accesslog.bufferingsize=100"
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.file.directory=/configuration"
- "--providers.file.filename=dynamic_conf.toml"
- "--providers.file.watch=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.mytlschallenge.acme.tlschallenge=true"
#- "--certificatesresolvers.mytlschallenge.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
- "--certificatesresolvers.mytlschallenge.acme.email=xxx@yahoo.com"
- "--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json"
volumes:
- logs:/var/log
- "./letsencrypt:/letsencrypt"
- "./configuration:/configuration"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
networks:
- web
ports:
- 80:80
- 443:443
networks:
web:
external: true
volumes:
logs: {}
Code language: PHP (php)
Dynamic Configuration TOML
[http]
[http.routers.my-api]
entryPoints = ["websecure"]
rule = "Host(`monitor.epidemiology.tech`)"
service = "api@internal"
middlewares = ["secured"]
[http.routers.my-api.tls]
options = "default"
certResolver = "mytlschallenge"
[http.middlewares]
[http.middlewares.secured.chain]
middlewares = ["safe-ipwhitelist", "auth"]
[http.middlewares.secureHeader]
[http.middlewares.secureHeader.headers]
frameDeny = true
stsSeconds = 31536000
stsPreload = true
stsIncludeSubdomains = true
browserXssFilter = true
contentTypeNosniff = true
forceSTSHeader = true
contentSecurityPolicy = "frame-ancestors 'self'"
isDevelopment = false
customFrameOptionsValue = "SAMEORIGIN"
[http.middlewares.httpsRedirect]
[http.middlewares.httpsRedirect.redirectScheme]
scheme = "https"
permanent = true
[http.middlewares.compression]
[http.middlewares.compression.compress]
excludedContentTypes = ["text/event-stream"]
minResponseBodyBytes = 1200
[http.middlewares.auth.basicAuth]
users = [
"Ssssssss:$XXXXXxxxxxxxxxxxxx"
]
[http.middlewares.safe-ipwhitelist.ipWhiteList]
sourceRange = ["XX.XX.XX.XX/24", "YYY.YYY.YYY.YYY/24", "ZZZ.ZZZ.ZZZ.ZZZ/24"]
[tls]
[tls.options]
[tls.options.default]
minVersion = "VersionTLS12"
cipherSuites = [
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
]
Code language: PHP (php)
The Key changes
- SSLredirect has been removed from secureHeader.headers as it is depreciated
- added a new http middleware called
httpsRedirect
- Added a new http middleware called
compression
which enables gZip compress on response - Added following to
headers
middleware- contentSecurityPolicy = “frame-ancestors ‘self'”
- based on MDN . The HTTP
Content-Security-Policy
(CSP)frame-ancestors
allows use to specify what parent source may embed a page using<frame>
,<iframe>
,<object>
, or<embed>
. - This enables page-preview in page builders to work where iFrame is being used.
'self'
refers to the origin from which the protected document is being served, including the same URL scheme and port number.
- based on MDN . The HTTP
- isDevelopment = false
- customFrameOptionsValue = “SAMEORIGIN”
- The
customFrameOptionsValue
allows theX-Frame-Options
header value to be set with a custom value. SAMEORIGIN
ensures that the page can only be displayed if all ancestor frames are same origin to the page itself.- The
Content-Security-Policy
HTTP header has aframe-ancestors
directive which obsoletes this header for supporting browsers. We are adding the CSP header but this one is being added also for older browsers
- The
- contentSecurityPolicy = “frame-ancestors ‘self'”
Using the middleware in a WordPress container
version: "3"
services:
newDomain:
image: wordpress:6.2.2-php8.2-apache
environment:
WORDPRESS_DB_HOST: dbWP
WORDPRESS_DB_USER: XXXXXXXX
WORDPRESS_DB_PASSWORD: XXXXXXXXXXX
WORDPRESS_DB_NAME: XXXXXXXXX
labels:
- "traefik.enable=true"
- "traefik.docker.network=web"
- "traefik.http.middlewares.newDomain-https.redirectscheme.scheme=https"
- "traefik.http.routers.newDomain-http.entrypoints=web"
- "traefik.http.routers.newDomain-http.rule=Host(`newDomain.com`, `www.newDomain.com`)"
- "traefik.http.routers.newDomain-http.middlewares=newDomain-https@docker"
- "traefik.http.routers.newDomain.middlewares=secureHeader@file, compression@file, httpsRedirect@file"
- "traefik.http.routers.newDomain.entrypoints=websecure"
- "traefik.http.routers.newDomain.rule=Host(`newDomain.com`, `www.newDomain.com`)"
- "traefik.http.routers.newDomain.tls=true"
- "traefik.http.routers.newDomain.tls.options=default"
- "traefik.http.routers.newDomain.tls.certresolver=mytlschallenge"
# Create a middleware named `customCors` for CORS headers
# - "traefik.http.middlewares.customCors.headers.accesscontrolalloworiginlist=https://newDomain.com, https://www.newDomain.com"
# Apply the middleware named `customCors` to the router named `newDomain`
# - "traefik.http.routers.newDomain.middlewares=customCors"
# Apply the common TRAEFIC2 configuration file middleware named `dataCompress` for gZip to the router named `newDomain`
# - "traefik.http.routers.newDomain.middlewares=test-compress@file"
volumes:
- ./newDomain/wordpress_files:/var/www/html
- ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
networks:
- internal
- web
networks:
web:
external: true
internal:
external: true
Code language: PHP (php)
Folder structure for WordPress container
├── docker-compose.yml
├── newDomain
│ └── wordpress_files
└── uploads.ini
Code language: CSS (css)
uploads.ini
file_uploads = On
memory_limit = 512M
upload_max_filesize = 2M
post_max_size = 2M
max_execution_time = 60
Database Container
version: "3"
services:
dbWP:
image: mariadb:10.5
environment:
# MYSQL_USER: XXXXXXXXXXXXXXXXXXXXXXXX
# MYSQL_PASSWORD: XXXXXXXXXXXXXXXXXXXX
# MYSQL_DATABASE: XXXXXXXXXXXXXXXX
MYSQL_RANDOM_ROOT_PASSWORD: '1'
networks:
- internal
labels:
- traefik.enable=false
volumes:
- ./datadir:/var/lib/mysql
networks:
web:
external: true
internal:
external: true
Code language: PHP (php)
Refer to steps in my first post about how to know your mySQL root password the first time the container is created, and how to create databases and users for WordPress sites using terminal.
docker ps -a
docker logs dbContainerName | grep password
# CREATE DATABASE AND USER FOR WORDPRESS
docker inspect logs dbContainerName | grep IPA
# Note the IP address
mysql -u root -h XXX.XXX.XX.XX -p
# Enter the root password to reach the database shell >
CREATE USER 'MariaDbUser'@'%' IDENTIFIED BY 'MariaDbUserPassword';
GRANT ALL ON blog1.* TO 'username'@'%';
flush privileges;
Code language: PHP (php)
Adminer Container
This is a GUI web interface which can be used to manage the database. It is working as a subdomain which needs to be created in the DNS settings of the hosting provider. Normally, the container must be switched off. Switch it on only when needed. A few minutes of effort are well worth the safety gained.
version: '3'
services:
adminer:
image: adminer:latest
container_name: adminer2023
security_opt:
- no-new-privileges:true
environment:
ADMINER_DEFAULT_SERVER: dbWP
ADMINER_PLUGINS: 'tables-filter tinymce'
ADMINER_DESIGN: galkaev
labels:
- "traefik.enable=true"
- "traefik.docker.network=web"
- "traefik.http.middlewares.adminer-https.redirectscheme.scheme=https"
- "traefik.http.routers.adminer-http.entrypoints=web"
- "traefik.http.routers.adminer-http.rule=Host(`adminer.newDomain.com`)"
- "traefik.http.routers.adminer-http.middlewares=adminer-https@docker"
- "traefik.http.routers.adminer.middlewares=secureHeader@file"
- "traefik.http.routers.adminer.entrypoints=websecure"
- "traefik.http.routers.adminer.rule=Host(`adminer.newDomain.com`)"
- "traefik.http.routers.adminer.tls=true"
- "traefik.http.routers.adminer.tls.options=default"
- "traefik.http.routers.adminer.tls.certresolver=mytlschallenge"
- "traefik.http.services.adminer.loadbalancer.server.port=8080"
networks:
- internal
- web
networks:
web:
external: true
internal:
external: true
Code language: JavaScript (javascript)
Container recreation when testing the Traefik/wordpress/adminer containers
docker-compose down
docker-compose pull
docker-compose up --build -d
docker-compose up -d
Working with containers using terminals
executing bash commands inside containers
docker exec -it dbContainerName bash
View the enabled Modules
apache2ctl -M
# View the prefork module settings
cat /etc/apache2/mods-enabled/mpm_prefork.conf
# https://www.jeffgeerling.com/blog/3-small-tweaks-make-apache-fly
# Apache thread memory consumption
ps aux | grep 'httpd' | awk '{print $6/1024 " MB";}'
ps aux | grep 'httpd' | awk '{print $6/1024;}' | awk '{avg += ($1 - avg) / NR;} END {print avg " MB";}'
Code language: PHP (php)
Copying and editing files inside containers
# From container to Host and Edit
docker cp dbContainerName:/etc/apache2/apache2.conf .
cp apache2.conf apache2.conf.default
nano apache2.conf
# From host to container
docker cp apache2.conf dbContainerName:/etc/apache2/apache2.conf
# From container to Host and Edit
docker cp dbContainerName:/etc/apache2/mods-available/mpm_prefork.conf .
cp mpm_prefork.conf mpm_prefork.conf.default
nano mpm_prefork.conf
cp mpm_prefork.conf dbContainerName:/etc/apache2/mods-available/mpm_prefork.conf
Code language: PHP (php)