# 创建主目录
mkdir -p /opt/wordpress
cd /opt/wordpress
# 创建所有需要的子目录
mkdir -p {db_data,wordpress_data,nginx-conf,certs,backups,redis_data}
# 创建环境变量文件(密码以混合形式加密存储)
cat > .env << 'EOF'
MYSQL_ROOT_PASSWORD=ENCRYPTED_PASSWORD_$(echo -n "guojiulin.cn" | base64)_END
MYSQL_DATABASE=wordpress
MYSQL_USER=wordpress
MYSQL_PASSWORD=ENCRYPTED_PASSWORD_$(echo -n "guojiulin.cn" | base64)_END
WORDPRESS_DB_HOST=db:3306
WORDPRESS_DB_USER=wordpress
WORDPRESS_DB_PASSWORD=ENCRYPTED_PASSWORD_$(echo -n "guojiulin.cn" | base64)_END
WORDPRESS_DB_NAME=wordpress
REDIS_PASSWORD=ENCRYPTED_PASSWORD_$(echo -n "guojiulin.cn" | base64)_END
EOF
# 创建密码解密脚本
cat > decrypt_password.sh << 'EOF'
#!/bin/bash
echo "$1" | awk -F'ENCRYPTED_PASSWORD_|_END' '{print $2}' | base64 -d
EOF
chmod +x decrypt_password.sh
cat > nginx-conf/nginx.conf << 'EOF'
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 4096;
multi_accept on;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main buffer=32k flush=5s;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 1000;
types_hash_max_size 2048;
server_tokens off;
client_max_body_size 64M;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_min_length 256;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=WORDPRESS:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
upstream wordpress {
server wordpress:9000;
keepalive 32;
}
server {
listen 80;
server_name guijiulin.cn www.guijiulin.cn;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name guijiulin.cn www.guijiulin.cn;
ssl_certificate /etc/nginx/ssl/guijiulin.cn.crt;
ssl_certificate_key /etc/nginx/ssl/guijiulin.cn.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
add_header Strict-Transport-Security "max-age=63072000" always;
add_header X-Frame-Options SAMEORIGIN always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
root /var/www/html;
index index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
fastcgi_pass wordpress;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_param HTTPS on;
fastcgi_buffers 256 16k;
fastcgi_buffer_size 128k;
fastcgi_connect_timeout 5s;
fastcgi_send_timeout 600s;
fastcgi_read_timeout 600s;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;
fastcgi_cache WORDPRESS;
fastcgi_cache_valid 200 301 302 60m;
fastcgi_cache_valid 404 1m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
add_header X-Cache $upstream_cache_status;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 365d;
add_header Cache-Control "public, immutable";
access_log off;
}
location ~ /\.ht {
deny all;
}
location = /xmlrpc.php {
deny all;
access_log off;
log_not_found off;
}
location ~* wp-config.php {
deny all;
}
location ~* readme.html {
deny all;
}
location ~* license.txt {
deny all;
}
}
}
EOF
cat > uploads.ini << 'EOF'
upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
max_execution_time = 300
max_input_time = 300
max_input_vars = 5000
realpath_cache_size = 4096K
realpath_cache_ttl = 600
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2
opcache.fast_shutdown=1
EOF
cat > mysql.cnf << 'EOF'
[mysqld]
max_allowed_packet=256M
innodb_buffer_pool_size=2G
innodb_log_file_size=512M
innodb_file_per_table=1
innodb_flush_log_at_trx_commit=2
innodb_flush_method=O_DIRECT
innodb_buffer_pool_instances=8
innodb_read_io_threads=64
innodb_write_io_threads=64
innodb_io_capacity=2000
innodb_io_capacity_max=4000
query_cache_type=1
query_cache_size=128M
query_cache_limit=2M
thread_cache_size=32
table_open_cache=2000
max_connections=200
slow_query_log=1
slow_query_log_file=/var/lib/mysql/slow.log
long_query_time=2
log_queries_not_using_indexes=1
performance_schema=ON
EOF
cat > redis.conf << 'EOF'
maxmemory 1gb
maxmemory-policy allkeys-lru
appendonly yes
appendfsync everysec
save 900 1
save 300 10
save 60 10000
activerehashing yes
hz 10
tcp-keepalive 300
EOF
cat > docker-compose.yml << 'EOF'
version: '3.8'
services:
db:
image: mariadb:10.6
container_name: wordpress_db
restart: always
env_file:
- .env
command:
- --max-allowed-packet=256M
- --innodb-buffer-pool-size=2G
- --innodb-log-file-size=512M
- --innodb-file-per-table=1
- --innodb-flush-log-at-trx-commit=2
- --innodb-flush-method=O_DIRECT
- --performance-schema=ON
volumes:
- ./db_data:/var/lib/mysql
- ./backups:/backups
- ./mysql.cnf:/etc/mysql/conf.d/mysql.cnf:ro
networks:
- wp-network
deploy:
resources:
limits:
memory: 4G
cpus: '2'
reservations:
memory: 1G
cpus: '0.5'
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
timeout: 20s
retries: 10
redis:
image: redis:alpine
container_name: wordpress_redis
restart: always
command: redis-server /usr/local/etc/redis/redis.conf
volumes:
- ./redis_data:/data
- ./redis.conf:/usr/local/etc/redis/redis.conf:ro
networks:
- wp-network
deploy:
resources:
limits:
memory: 1G
reservations:
memory: 256M
healthcheck:
test: ["CMD", "redis-cli", "ping"]
timeout: 10s
retries: 5
wordpress:
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
image: wordpress:6.4-php8.2-fpm-alpine
container_name: wordpress_app
restart: always
env_file:
- .env
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: ENCRYPTED_PASSWORD_$(echo -n "guojiulin.cn" | base64)_END
WORDPRESS_DB_NAME: wordpress
WORDPRESS_CONFIG_EXTRA: |
define('WP_MEMORY_LIMIT', '256M');
define('WP_MAX_MEMORY_LIMIT', '512M');
define('FORCE_SSL_ADMIN', true);
define('FORCE_SSL_LOGIN', true);
$_SERVER['HTTPS'] = 'on';
define('WP_DEBUG', false);
define('WP_DEBUG_LOG', false);
define('WP_DEBUG_DISPLAY', false);
define('WP_AUTO_UPDATE_CORE', true);
define('AUTOMATIC_UPDATER_DISABLED', false);
define('WP_HOME', 'https://guijiulin.cn');
define('WP_SITEURL', 'https://guijiulin.cn');
define('WP_CACHE', true);
define('WP_REDIS_HOST', 'redis');
define('WP_REDIS_PORT', 6379);
define('WP_REDIS_TIMEOUT', 1);
define('WP_REDIS_READ_TIMEOUT', 1);
define('WP_REDIS_DATABASE', 0);
volumes:
- ./wordpress_data:/var/www/html
- ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
- ./object-cache.php:/var/www/html/wp-content/object-cache.php
networks:
- wp-network
deploy:
resources:
limits:
memory: 1G
cpus: '1'
reservations:
memory: 256M
cpus: '0.25'
nginx:
depends_on:
- wordpress
image: nginx:alpine
container_name: wordpress_nginx
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx-conf/nginx.conf:/etc/nginx/nginx.conf:ro
- ./certs:/etc/nginx/ssl:ro
- ./wordpress_data:/var/www/html:ro
- ./nginx-conf/cache:/var/cache/nginx
- ./nginx-conf/logs:/var/log/nginx
networks:
- wp-network
deploy:
resources:
limits:
memory: 512M
reservations:
memory: 128M
healthcheck:
test: ["CMD", "nginx", "-t"]
interval: 30s
timeout: 10s
retries: 3
networks:
wp-network:
driver: bridge
driver_opts:
com.docker.network.driver.mtu: 1500
EOF
cat > object-cache.php << 'EOF'
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
function wp_cache_add( $key, $data, $group = '', $expire = 0 ) {
global $wp_object_cache;
return $wp_object_cache->add( $key, $data, $group, $expire );
}
function wp_cache_close() {
return true;
}
function wp_cache_decr( $key, $offset = 1, $group = '' ) {
global $wp_object_cache;
return $wp_object_cache->decr( $key, $offset, $group );
}
function wp_cache_delete( $key, $group = '' ) {
global $wp_object_cache;
return $wp_object_cache->delete( $key, $group );
}
function wp_cache_flush() {
global $wp_object_cache;
return $wp_object_cache->flush();
}
function wp_cache_get( $key, $group = '', $force = false, &$found = null ) {
global $wp_object_cache;
return $wp_object_cache->get( $key, $group, $force, $found );
}
function wp_cache_incr( $key, $offset = 1, $group = '' ) {
global $wp_object_cache;
return $wp_object_cache->incr( $key, $offset, $group );
}
function wp_cache_init() {
global $wp_object_cache;
if ( ! ( $wp_object_cache instanceof WP_Object_Cache ) ) {
$wp_object_cache = new WP_Object_Cache();
}
}
function wp_cache_replace( $key, $data, $group = '', $expire = 0 ) {
global $wp_object_cache;
return $wp_object_cache->replace( $key, $data, $group, $expire );
}
function wp_cache_set( $key, $data, $group = '', $expire = 0 ) {
global $wp_object_cache;
return $wp_object_cache->set( $key, $data, $group, $expire );
}
function wp_cache_switch_to_blog( $blog_id ) {
global $wp_object_cache;
return $wp_object_cache->switch_to_blog( $blog_id );
}
function wp_cache_add_global_groups( $groups ) {
global $wp_object_cache;
$wp_object_cache->add_global_groups( $groups );
}
function wp_cache_add_non_persistent_groups( $groups ) {
global $wp_object_cache;
$wp_object_cache->add_non_persistent_groups( $groups );
}
class WP_Object_Cache {
private $redis;
private $cache = [];
private $global_groups = [];
private $non_persistent_groups = [];
private $blog_prefix;
private $default_expiration = 3600;
public function __construct() {
$this->blog_prefix = get_current_blog_id();
try {
$this->redis = new Redis();
$this->redis->connect(
defined('WP_REDIS_HOST') ? WP_REDIS_HOST : 'redis',
defined('WP_REDIS_PORT') ? WP_REDIS_PORT : 6379,
defined('WP_REDIS_TIMEOUT') ? WP_REDIS_TIMEOUT : 1
);
if ( defined('WP_REDIS_PASSWORD') && WP_REDIS_PASSWORD ) {
$this->redis->auth(WP_REDIS_PASSWORD);
}
if ( defined('WP_REDIS_DATABASE') ) {
$this->redis->select(WP_REDIS_DATABASE);
}
$this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);
$this->redis->setOption(Redis::OPT_READ_TIMEOUT, defined('WP_REDIS_READ_TIMEOUT') ? WP_REDIS_READ_TIMEOUT : 1);
} catch (Exception $e) {
$this->redis = false;
}
}
private function build_key( $key, $group = 'default' ) {
if ( empty($group) ) {
$group = 'default';
}
if ( in_array($group, $this->global_groups) ) {
$prefix = '';
} else {
$prefix = $this->blog_prefix . ':';
}
return $prefix . $group . ':' . $key;
}
public function add( $key, $data, $group = 'default', $expire = 0 ) {
if ( wp_suspend_cache_addition() ) {
return false;
}
$key = $this->build_key($key, $group);
if ( in_array($group, $this->non_persistent_groups) ) {
if ( isset($this->cache[$key]) ) {
return false;
}
$this->cache[$key] = $data;
return true;
}
if ( ! $this->redis ) {
return false;
}
if ( $this->redis->exists($key) ) {
return false;
}
$expire = $expire ?: $this->default_expiration;
return $this->redis->setex($key, $expire, $data);
}
public function decr( $key, $offset = 1, $group = 'default' ) {
$key = $this->build_key($key, $group);
if ( in_array($group, $this->non_persistent_groups) ) {
if ( ! isset($this->cache[$key]) || ! is_numeric($this->cache[$key]) ) {
return false;
}
$this->cache[$key] -= $offset;
return $this->cache[$key];
}
if ( ! $this->redis ) {
return false;
}
return $this->redis->decrBy($key, $offset);
}
public function delete( $key, $group = 'default' ) {
$key = $this->build_key($key, $group);
unset($this->cache[$key]);
if ( in_array($group, $this->non_persistent_groups) ) {
return true;
}
if ( ! $this->redis ) {
return false;
}
return (bool) $this->redis->del($key);
}
public function flush() {
$this->cache = [];
if ( ! $this->redis ) {
return false;
}
return $this->redis->flushDB();
}
public function get( $key, $group = 'default', $force = false, &$found = null ) {
$key = $this->build_key($key, $group);
if ( ! $force && isset($this->cache[$key]) ) {
$found = true;
return $this->cache[$key];
}
if ( in_array($group, $this->non_persistent_groups) ) {
$found = false;
return false;
}
if ( ! $this->redis ) {
$found = false;
return false;
}
$data = $this->redis->get($key);
if ( $data === false ) {
$found = false;
return false;
}
$found = true;
$this->cache[$key] = $data;
return $data;
}
public function incr( $key, $offset = 1, $group = 'default' ) {
$key = $this->build_key($key, $group);
if ( in_array($group, $this->non_persistent_groups) ) {
if ( ! isset($this->cache[$key]) || ! is_numeric($this->cache[$key]) ) {
return false;
}
$this->cache[$key] += $offset;
return $this->cache[$key];
}
if ( ! $this->redis ) {
return false;
}
return $this->redis->incrBy($key, $offset);
}
public function replace( $key, $data, $group = 'default', $expire = 0 ) {
$key = $this->build_key($key, $group);
if ( in_array($group, $this->non_persistent_groups) ) {
if ( ! isset($this->cache[$key]) ) {
return false;
}
$this->cache[$key] = $data;
return true;
}
if ( ! $this->redis ) {
return false;
}
if ( ! $this->redis->exists($key) ) {
return false;
}
$expire = $expire ?: $this->default_expiration;
return $this->redis->setex($key, $expire, $data);
}
public function set( $key, $data, $group = 'default', $expire = 0 ) {
$key = $this->build_key($key, $group);
$this->cache[$key] = $data;
if ( in_array($group, $this->non_persistent_groups) ) {
return true;
}
if ( ! $this->redis ) {
return false;
}
$expire = $expire ?: $this->default_expiration;
return $this->redis->setex($key, $expire, $data);
}
public function switch_to_blog( $blog_id ) {
$this->blog_prefix = $blog_id;
}
public function add_global_groups( $groups ) {
$groups = (array) $groups;
$this->global_groups = array_merge($this->global_groups, $groups);
$this->global_groups = array_unique($this->global_groups);
}
public function add_non_persistent_groups( $groups ) {
$groups = (array) $groups;
$this->non_persistent_groups = array_merge($this->non_persistent_groups, $groups);
$this->non_persistent_groups = array_unique($this->non_persistent_groups);
}
}
wp_cache_init();
EOF
# 设置目录权限
chmod -R 755 /opt/wordpress
chown -R www-data:www-data /opt/wordpress/wordpress_data
# 启动服务
cd /opt/wordpress
docker-compose up -d
# 查看服务状态
docker-compose ps
# 查看日志
docker-compose logs -f
SSL证书:需要将您的SSL证书(guijiulin.cn.crt和guijiulin.cn.key)放到 /opt/wordpress/certs/ 目录
域名配置:在 nginx.conf 文件中,将 guijiulin.cn 替换为您的实际域名
性能调优:根据服务器实际资源调整 docker-compose.yml 中的内存和CPU限制
Redis密码:如果需要Redis密码,在 .env 文件中取消注释并设置
性能优化:
安全性:
高可用性:
监控和日志:
这个配置将为您的WordPress站点提供极快的访问速度和优秀的性能表现。