chore: initialize dockerized wordpress stack

This commit is contained in:
2025-11-16 10:42:14 +08:00
commit 654956a154
6 changed files with 246 additions and 0 deletions

26
.gitignore vendored Normal file
View File

@@ -0,0 +1,26 @@
# Environment files
.env
.env.*
*.env
# Local docker data volumes
/db_data/
/wordpress_data/
/wordpress_data/wp-config.php
/redis_data/
# WordPress exports / backups
*.sql
*.tar
*.tar.gz
*.tgz
*.zip
# Editor / OS cruft
.DS_Store
Thumbs.db
.idea/
.vscode/
# Log files
*.log

48
README.md Normal file
View File

@@ -0,0 +1,48 @@
# DigitechFlow WordPress Stack
This repository contains a hardened Docker Compose stack for the DigitechFlow WordPress deployment. It runs MySQL, WordPress (PHP-FPM), Nginx, and Valkey (Redis-compatible cache) with sensible defaults.
## Prerequisites
- Docker Engine + Docker Compose V2
- Traefik network (`traefik_default`) already present for routing/SSL
- Host directories writable for `db_data/`, `wordpress_data/`, and `redis_data/`
## Getting Started
1. Copy the environment template and fill in secrets:
```bash
cp .env.example .env
# Edit .env to use strong unique values (DB creds, salts)
```
2. Bring up the stack:
```bash
docker compose up -d
```
3. Access WordPress via the configured Traefik domain (e.g., https://digitechflow.com).
## Services
- **db**: `mysql:latest` with persistent volume `db_data/`.
- **wordpress**: `wordpress:php8.3-fpm` serving PHP over FastCGI.
- **wordpress_nginx**: `nginx:latest` front-end with custom config tuned for Traefik and FastCGI.
- **redis**: `valkey/valkey:latest` for object caching with persistence and healthcheck.
## Configuration Highlights
- Secrets and database settings sourced from `.env`; the template (`.env.example`) documents required keys.
- `config/nginx/default.conf` contains gzip, caching, and FastCGI tuning. Adjust if you need custom routes.
- `wordpress.ini` sets PHP limits and Opcache recommendations.
- Local data directories (`db_data/`, `wordpress_data/`, `redis_data/`) plus `wp-config.php` are gitignored to prevent leaking content/secrets.
## Operations
- Update images: `docker compose pull && docker compose up -d`.
- View logs: `docker compose logs -f <service>`.
- Run WordPress CLI tasks: `docker compose exec wordpress wp <command>` (install WP-CLI first if needed).
## Security Notes
- Always use unique, strong passwords in `.env` and rotate them periodically.
- Regenerate WordPress auth salts via https://api.wordpress.org/secret-key/1.1/salt/ and store them in `.env`.
- Ensure Traefik enforces HTTPS and apply rate limiting/WAF middleware as needed.
- Schedule backups (database dumps + `wordpress_data`) off-host; the stack does not include automated backups by default.
## Troubleshooting
- Bad gateway from Nginx usually means PHP-FPM isnt reachable; check `docker compose logs wordpress wordpress_nginx`.
- If Compose warns about `version: '3'`, you can remove that line—its optional with Compose V2.
- Ensure the Traefik network exists: `docker network ls | grep traefik_default`.

49
config/nginx/default.conf Normal file
View File

@@ -0,0 +1,49 @@
server {
listen 80;
server_name _;
root /var/www/html;
index index.php index.html;
# Trust real client IPs forwarded by Traefik
set_real_ip_from 172.19.0.0/16;
set_real_ip_from 172.21.0.0/16;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
# Basic compression for text assets
gzip on;
gzip_types text/plain text/css application/json application/javascript application/xml+rss image/svg+xml;
gzip_comp_level 5;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass wordpress:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for;
fastcgi_param HTTP_X_FORWARDED_PROTO $http_x_forwarded_proto;
fastcgi_param HTTPS $http_x_forwarded_proto;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_read_timeout 120s;
fastcgi_send_timeout 120s;
fastcgi_connect_timeout 60s;
}
location ~* \.(?:css|js|jpg|jpeg|gif|png|svg|ico|webp|avif)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
access_log off;
try_files $uri =404;
}
client_max_body_size 64m;
sendfile on;
keepalive_timeout 65;
}

12
config/redis.conf Normal file
View File

@@ -0,0 +1,12 @@
# Persistent Valkey configuration tuned for WordPress object cache.
appendonly yes
appendfsync everysec
save 900 1
save 300 10
save 60 10000
maxmemory 256mb
maxmemory-policy allkeys-lru
protected-mode no
bind 0.0.0.0
port 6379
dir /data

99
docker-compose.yaml Normal file
View File

@@ -0,0 +1,99 @@
services:
# MySQL Service
db:
image: mysql:latest
container_name: digitechflow_db
volumes:
- ./db_data:/var/lib/mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
networks:
- wordpress_network
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 5s
retries: 10
# WordPress PHP-FPM Service
wordpress:
depends_on:
db:
condition: service_healthy
image: wordpress:php8.3-fpm
container_name: digitechflow_wordpress
restart: unless-stopped
volumes:
- ./wordpress_data:/var/www/html
- ./wordpress.ini:/usr/local/etc/php/conf.d/wordpress.ini
expose:
- "9000"
environment:
WORDPRESS_DB_HOST: ${WORDPRESS_DB_HOST}
WORDPRESS_DB_USER: ${WORDPRESS_DB_USER}
WORDPRESS_DB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
WORDPRESS_DB_NAME: ${WORDPRESS_DB_NAME}
WORDPRESS_REDIS_HOST: ${WORDPRESS_REDIS_HOST}
networks:
- wordpress_network
extra_hosts:
- "host.docker.internal:host-gateway" # For crowdsec plugin to connect to host crowdsec api
# Nginx front-end for WordPress (Traefik faces this container)
wordpress_nginx:
depends_on:
wordpress:
condition: service_started
image: nginx:latest
container_name: digitechflow_nginx
restart: unless-stopped
volumes:
- ./wordpress_data:/var/www/html:ro
- ./config/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
networks:
- wordpress_network
- traefik_default
labels:
- "traefik.enable=true"
- "traefik.http.routers.digitechflow.rule=Host(`digitechflow.com`)"
- "traefik.http.routers.digitechflow.entrypoints=websecure"
- "traefik.http.routers.digitechflow.middlewares=crowdsec@file,retry-fast@file"
- "traefik.http.routers.digitechflow.tls.certresolver=letsencrypt"
- "traefik.http.services.digitechflow.loadbalancer.server.port=80"
- "traefik.http.services.digitechflow.loadbalancer.serversTransport=fast-upstreams@file"
- "traefik.docker.network=traefik_default"
redis:
image: valkey/valkey:latest
container_name: digitechflow_valkey
restart: unless-stopped
volumes:
- ./redis_data:/data
- ./config/redis.conf:/usr/local/etc/redis/redis.conf:ro
command: ["valkey-server", "/usr/local/etc/redis/redis.conf"]
networks:
- wordpress_network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
# Volumes for persistent data
volumes:
db_data:
wordpress_data:
redis_data:
# Network for communication between services
networks:
wordpress_network:
driver: bridge
ipam:
config:
- subnet: 172.21.0.0/16
gateway: 172.21.0.1
traefik_default:
external: true # Assumes Traefik uses an existing network

12
wordpress.ini Normal file
View File

@@ -0,0 +1,12 @@
file_uploads = On
memory_limit = 512M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 300
max_input_time = 1000
; Opcache tuning for better PHP-FPM performance
opcache.enable=1
opcache.memory_consumption=192
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.validate_timestamps=0