Lưu trữ WordPress qua HTTPS với Docker
CẬP NHẬT 13/10/2020: Xin chào! Rừng từ tương lai đây! Tôi không còn sử dụng thiết lập này nữa. Và, tôi không có ý định cập nhật nó. Vì tôi không còn duy trì điều này cho chính mình nữa và vì nó là một giải pháp rất tùy chỉnh, nên tôi không có thời gian để tạo một kho lưu trữ cho nó.
Giải pháp này ít nhất là 3 năm tuổi. Nếu bạn buộc phải sử dụng phiên bản cũ của WordPress và giải pháp này phù hợp với bạn, tôi rất vui vì đã giúp được bạn. Mặt khác, nếu bạn đang sử dụng phiên bản mới hơn của WordPress, Nginx, Docker hoặc Certbot, có thể có một số thông tin hữu ích ở đây, nhưng ngoài ra, tôi còn chúc bạn may mắn!
Chúc mừng! 😄
Mới ngày hôm trước , tôi đã chuyển danh mục đầu tư của mình sang một máy chủ riêng và bắt đầu phân phối nó qua HTTPS. Tôi đã rất hấp dẫn khi tất cả đã hoàn thành! Tôi muốn nói một chút về những bước tôi đã thực hiện, vì tôi đã tìm thấy một số lỗi khó chịu trên đường đi. Đây không phải là hướng dẫn từng bước, thay vào đó tôi đang chia sẻ các cấu hình mà cuối cùng nó đã hoạt động cho tôi.
Tôi sử dụng example.com
như một trình giữ chỗ ở đây. Nếu bạn đang đọc điều này và cố gắng thiết lập của riêng bạn hoạt động, bạn sẽ thay thế example.com
bằng tên miền của riêng mình. Ngoài ra, mặc dù tôi nghi ngờ nó cần phải được nói, không sử dụng root
làm mật khẩu MySQL của bạn.
Contents
Ngăn xếp máy chủ
Tôi sử dụng Docker để cô lập các máy chủ của mình, để tất cả chúng đều có thể có môi trường riêng. Điều đó, và nếu tôi làm hỏng thứ gì đó trên vùng chứa Docker, tôi có thể xây dựng lại nó. Ngoài ra, tôi sử dụng Docker Compose để xử lý việc nhóm các vùng chứa của mình lại với nhau.
Tôi đã chọn Nginx làm proxy và máy chủ web WordPress của mình. Lưu ý rằng proxy không cần thiết ở đây, nhưng tôi cần nó cho một số việc khác. Tôi muốn giữ mọi thứ nhất quán, vì vậy đó là lý do tại sao tôi chọn sử dụng Nginx trên diện rộng.
Nếu bạn đang cố gắng đạt được thiết lập tương tự, nhưng sans-proxy, bạn cũng có thể cung cấp chứng chỉ SSL cho máy chủ Nginx của vùng chứa WordPress của mình và thêm vào các khối máy chủ thích hợp để hỗ trợ SSL. Tôi đề cập đến những thứ bên dưới trong phần Nginx Proxy Container .
Đối với chứng chỉ SSL của tôi, tôi đang sử dụng Let’s Encrypt qua Certbot . Đó là một công cụ nhỏ đáng yêu tự động hóa toàn bộ quy trình đăng ký chứng chỉ.
Tổng quan về cấu hình soạn thảo Docker
^ ToC
Các phần sau liệt kê tất cả các cấu hình cần thiết cho các vùng chứa sau:
- proxy:
- nginx
- wordpress:
- nginx
- wordpress
- mariadb
Vùng chứa Proxy Nginx
docker-compos.yml
version: '3.3'
services:
nginx-proxy:
container_name: nginx-proxy
build: .
image: nginx-proxy:0.0.2
ports:
- "80:80"
- "443:443"
volumes:
- "./etc/letsencrypt/:/etc/letsencrypt/"
- "./etc/ssl/:/etc/ssl/"
command: bash -c "startup.sh"
restart: always
Vùng chứa sử dụng Dockerfile liền kề để tạo hình ảnh nginx-proxy tùy chỉnh. Bộ chứa hiển thị cổng 80
và cổng 443
cho máy chủ. Khi vùng chứa được đưa lên, nó sẽ gắn hai thư mục cục bộ vào /etc/letsencrypt/
và các /etc/ssl/
thư mục trên vùng chứa tương ứng. Sau đó, lệnh khởi động mặc định ( nginx -g 'daemon off;'
) được ghi đè để chạy startup.sh
tệp. Cuối cùng, vùng chứa được định cấu hình để khởi động lại bất cứ khi nào nó hoạt động ngay bây giờ, thông qua restart: always
đường truyền.
Dockerfile
FROM nginx:1.13.5-alpine
LABEL maintainer="Forest Hoffman<forestjhoffman@gmail.com>"
##
# setting necessary server configurations
##
# add curl and other necessary packages for openssl and certbot
RUN apk add --update \
curl \
bash \
openssl \
certbot \
python \
py-pip \
&& pip install --upgrade pip \
&& pip install 'certbot-nginx' \
&& pip install 'pyopenssl'
RUN addgroup staff
RUN addgroup www-data
RUN adduser -h /home/dev/ -D -g "" -G staff dev
RUN adduser -S -H -g "" -G www-data www-data
RUN echo dev:trolls | chpasswd
##
# copying nginx configuration file
##
COPY nginx.conf /etc/nginx/nginx.conf
RUN chown root:staff /etc/nginx/nginx.conf
# adds certbot cert renewal job to cron
COPY crontab /tmp/crontab-certbot
RUN (crontab -l; cat /tmp/crontab-certbot) | crontab -
# copies over the startup file which handles initializing the nginx
# server and the SSL certification process (if necessary)
COPY startup.sh /bin/startup.sh
RUN chown root:root /bin/startup.sh
RUN chmod ug+rx /bin/startup.sh
RUN chmod go-w /bin/startup.sh
Dockerfile sẽ bao gồm tất cả các yêu cầu cần thiết để chạy Certbot trong vùng chứa. Nó cũng sẽ thêm một dòng vào cron của vùng chứa sẽ chạy Certbot ở chế độ gia hạn, vào sáng sớm (theo thời gian hệ thống của vùng chứa Docker).
crontab
# Renew Let's Encrypt SSL Certificates that have < 30 days to go,
# in the morning (UTC time).
0 11 * * * /usr/bin/certbot renew --quiet
startup.sh
#!/bin/bash
#
# startup.sh
#
# Startup the nginx server. The server has to be active for the Let's Encrypt Certbot to
# register and install the certificates.
nginx -g "daemon on;"
# Checks that the SSL certificates are installed. If they are, renews any that are old, and
# installs them if not.
if [[ -d "/etc/letsencrypt/live/example.com" ]]; then
certbot renew --quiet
else
if ! [[ -d "/etc/letsencrypt/live/example.com" ]]; then
certbot --nginx -m your-email@ex.com --agree-tos --no-eff-email --redirect --expand -d example.com,www.example.com
fi
if ! [[ -f "/etc/ssl/certs/dhparam.pem" ]]; then
openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
fi
fi
# Shuts down the daemonized nginx server and fires up one in the foreground.
nginx -s stop && nginx -g 'daemon off;'
Tập startup.sh
lệnh được thiết kế để chạy bất cứ khi nào vùng chứa được đưa lên (tức là với docker-compose up
). Nó sẽ chỉ cố gắng đăng ký các chứng nhận nếu thư mục cho các chứng chỉ chưa có trong /etc/letsencrypt/live
thư mục trên vùng chứa. Các đường dẫn vào startup.sh
phải trùng với các đường dẫn trong tệp cấu hình Nginx. Nói về mà…
nginx.conf
user www-data;
worker_processes 1;
pid /run/nginx.pid;
events {
worker_connections 1024;
# multi_accept on;
}
http {
#sendfile on;
upstream docker-wordpress {
server nginx-wordpress:80;
}
# listen for HTTPS requests to example domain
server {
ssl_dhparam /etc/ssl/certs/dhparam.pem;
server_name example.com www.example.com;
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
location / {
proxy_pass http://docker-wordpress;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Proto https;
}
}
# handle ACME challenge from Certbot, and send HTTP requests to HTTPS
server {
listen 80;
server_name example.com www.example.com;
# listen for ACME challenge from Certbot
location ^~ /.well-known/acme-challenge/ {
# No HTTP authentication
allow all;
default_type "text/plain";
}
location = /.well-known/acme-challenge/ {
return 404;
}
# Redirect other HTTP traffic to HTTPS
location / {
access_log off;
return 301 https://$host$request_uri;
}
}
}
Điều này cấu hình proxy để lắng nghe các yêu cầu truy cập cổng 443
(ví dụ: yêu cầu sử dụng https://*
). Nếu các yêu cầu dành cho miền example.com
hoặc www.example.com
thì yêu cầu sẽ được chuyển đến http://docker-wordpress
máy chủ. Máy http://docker-wordpress
chủ “ngược dòng” được định nghĩa là cổng 80
của vùng chứa được kết nối nginx-wordpress
. Việc kết nối các vùng chứa với nhau được thực hiện bằng cách sử dụng networks
khóa trong docker-compose.yml
tệp.
[Đã chỉnh sửa 12/05/17]: Tôi đã cập nhật tệp cấu hình Nginx ở trên để bao gồm một khối máy chủ cho phép proxy vượt qua thử thách ACME của Certbot. Điều này là bắt buộc để gia hạn chứng chỉ.
Mọi yêu cầu chuyển đến cổng 80
đều không sử dụng SSL (chỉ bình thường http://*
), vì vậy những yêu cầu đó được chuyển hướng đến cổng 443
bằng cách buộc sử dụng HTTPS trong url.
Khối này …
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
Cho biết nơi chứng chỉ SSL cho các miền mong muốn sẽ nằm trên vùng chứa proxy.
Các vùng chứa WordPress
Lưu ý rằng tôi đã chia nhỏ các cấu hình vùng chứa trong các phần phụ bên dưới, nhưng chúng thực sự là tất cả từ cùng một docker-compose.yml
tệp.
Đây là những gì nó trông giống như tất cả cùng nhau.
docker-compos.yml
version: '3.3'
services:
nginx:
container_name: nginx-wordpress
image: nginx:latest
ports:
- '80'
volumes:
- ./nginx:/etc/nginx/conf.d
- ./nginx.conf:/etc/nginx/nginx.conf
- ./logs/nginx:/var/log/nginx
- ./wordpress:/var/www/html
depends_on:
- wordpress
restart: always
networks:
- nginxproxy_default
mysql:
container_name: mysql
image: mariadb
ports:
- '3306'
volumes:
- ./mysql:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=root
restart: always
networks:
- nginxproxy_default
wordpress:
container_name: wp
image: wordpress-prod:4.8.1-php5.6-fpm
ports:
- '9000'
volumes:
- ./wordpress:/var/www/html
environment:
- WORDPRESS_DB_NAME=wordpress
- WORDPRESS_TABLE_PREFIX=wpprefix_
- WORDPRESS_DB_HOST=mysql
- WORDPRESS_DB_PASSWORD=root
depends_on:
- mysql
restart: always
networks:
- nginxproxy_default
networks:
nginxproxy_default:
external: true
Điều quan trọng cần thấy ở đây là khóa cấp cao nhất networks
, cho phép mỗi vùng chứa kết nối với mạng mặc định của proxy . Mạng không được tạo bởi bất kỳ vùng chứa nào trong tệp soạn thảo này, vì vậy nginxproxy_default
mạng được xác định là mạng bên ngoài qua external: true
đường truyền.
Nginx cho Vùng chứa WordPress
docker-compos.yml
###
nginx:
container_name: nginx-wordpress
image: nginx:latest
ports:
- '80'
volumes:
- ./nginx:/etc/nginx/conf.d
- ./nginx.conf:/etc/nginx/nginx.conf
- ./logs/nginx:/var/log/nginx
- ./wordpress:/var/www/html
depends_on:
- wordpress
restart: always
networks:
- nginxproxy_default
###
Máy chủ nginx phía trước vùng chứa WordPress hiển thị cổng 80
và gắn bốn thư mục. Hai cái đầu tiên dành cho cấu hình nginx, cái tiếp theo là để bảo toàn nhật ký và cái cuối cùng là để bảo toàn cấu trúc tệp lõi WordPress.
nginx.conf
user www-data;
worker_processes auto;
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Đây chỉ là một tệp cấu hình cơ bản bao gồm bất kỳ tệp cấu hình bổ sung nào được gắn vào thư mục /etc/nginx/conf.d
và /etc/nginx/sites-enabled/
. Tệp này cũng chỉ định www-data
người dùng là người dùng mà Nginx nên sử dụng khi cố gắng cung cấp tệp. Điều này có nghĩa là cấu trúc tệp của máy chủ (được gắn vào /var/www/html
) phải được www-data
người dùng / nhóm có thể truy cập được.
nginx / wordpress.conf
server {
listen 80;
root /var/www/html;
index index.php;
access_log /var/log/nginx/wp-access.log;
error_log /var/log/nginx/wp-error.log;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.(png|jpg|jpeg|gif|svg)$ {
try_files $uri $uri/;
}
# Deny access to config.
location = /wp-config.php {
deny all;
}
# Deny access to htaccess.
location ~ /\. {
deny all;
}
# Directly allow access to /wp-admin/admin-ajax.php. This is necessary for
# WordPress to function on the admin side.
location ~* ^/wp-admin/admin-ajax.php$ {
try_files $uri =404;
fastcgi_intercept_errors on;
fastcgi_pass wordpress:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Allow access to all other PHP files.
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass wordpress:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
Máy chủ Nginx này đặc biệt phục vụ cho vùng chứa WordPress. Nó lắng nghe các yêu cầu chuyển 80
và gửi bất kỳ yêu cầu nào cho các tệp PHP (bao gồm các trang quản trị) đến vùng chứa WordPress trên cổng 9000
. Máy chủ nginx này không cần lắng nghe trên cổng 443
vì proxy đang xử lý xác thực SSL. Mọi yêu cầu đến đối với tệp trên máy chủ WordPress sẽ được định tuyến thông qua proxy.
Vùng chứa WordPress
docker-compos.yml
###
wordpress:
container_name: wp
image: wordpress-prod:4.8.1-php5.6-fpm
ports:
- '9000'
volumes:
- ./wordpress:/var/www/html
environment:
- WORDPRESS_DB_NAME=wordpress
- WORDPRESS_TABLE_PREFIX=wpprefix_
- WORDPRESS_DB_HOST=mysql
- WORDPRESS_DB_PASSWORD=root
depends_on:
- mysql
restart: always
networks:
- nginxproxy_default
###
Vùng chứa WordPress hiển thị cổng 9000
. Nó có một ổ đĩa được gắn kết để bảo vệ cấu trúc tệp WordPress. Nó cũng có bốn biến môi trường tương ứng với cơ sở dữ liệu được kết nối. Lưu ý rằng WORDPRESS_DB_HOST
tên giống với tên của vùng chứa mysqlcontainer_name
được kết nối .
wordpress / wp-config.php
<?php
###
// If we're behind a proxy server and using HTTPS, we need to alert WordPress of that fact
// see also http://codex.wordpress.org/Administration_Over_SSL#Using_a_Reverse_Proxy
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] = 'on';
// Force SSL in admin.
define('FORCE_SSL_ADMIN', true);
}
/* That's all, stop editing! Happy blogging. */
###
Bỏ qua các cấu hình mặc định, một vài dòng này có thể được đặt trước “dừng chỉnh sửa!” bình luận. Những dòng này buộc WordPress phải thực hiện các yêu cầu nội bộ bằng HTTPS, bao gồm cả phía quản trị viên.
Mariadb (MySQL) cho Vùng chứa WordPress
docker-compos.yml
###
mysql:
container_name: mysql
image: mariadb
ports:
- '3306'
volumes:
- ./mysql:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=root
restart: always
networks:
- nginxproxy_default
###
Sự khác biệt giữa vùng chứa Mariadb / MySQL và các vùng khác là mysql
khối lượng được gắn kết và biến môi trường mật khẩu gốc. Tất cả các cấu hình khác trong khối này rất giống với các thùng chứa trước đó.
Cài đặt chứng chỉ SSL với Certbot
Để chạy Certbot trên Nginx Proxy, trước tiên máy chủ phải được thiết lập và chạy. Giả sử rằng các chứng chỉ chưa có trong thư mục cục bộ của chúng ./etc/letsencrypt
, việc cố gắng chạy proxy bây giờ sẽ không thành công. Tôi phát hiện ra rằng để proxy có thể chạy, một số điều cần phải xảy ra.
1) nginxproxy_default
Mạng cần được tạo. Nếu proxy chưa từng được chạy trước đó, thì mạng không thể tồn tại. Tạo mạng bằng cách chạy như sau trong một thiết bị đầu cuối:
$ docker network create nginxproxy_default
2) Các vùng chứa WordPress cần phải chạy trước khi proxy có thể bắt đầu. Đầu tiên, hãy điều hướng đến vị trí docker-compose.yml
tệp dành cho vùng chứa WordPress. Sau đó, chạy phần sau trong một thiết bị đầu cuối:
$ docker-compose up -d
Lưu ý: -d
Cờ bắt đầu các vùng chứa ở chế độ không đầu, có nghĩa là bạn sẽ không thấy bất kỳ lỗi nào trừ khi bạn sử dụng lệnh docker-compose logs
hoặc kiểm tra trạng thái của các vùng chứa thông qua docker ps -a
.
3) Các đường dẫn đến chứng chỉ cần được ghi chú trước khi vùng chứa proxy có thể chạy Certbot. Trong proxy, nginx.conf
tôi đã phải nhận xét khối máy chủ chứa listen 443 ssl;
dòng và khối máy chủ xử lý chuyển hướng từ HTTP sang HTTPS. Ở vị trí của họ, tôi tạm thời nhập khối máy chủ này:
server {
listen 80;
server_name example.com www.example.com;
location / {
proxy_pass http://docker-wordpress;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}
Sau đó, Nginx Proxy có thể được tạo bằng docker-compose up --build
lệnh. Docker-comp khi đó sẽ sử dụng lệnh khởi động không phải mặc định, lệnh này sẽ chạy startup.sh
tập lệnh trong vùng chứa. Tôi khuyên bạn không nên sử dụng chế độ không đầu khi xây dựng proxy, bằng cách đó bạn có thể chắc chắn rằng Certbot có thể đăng ký chứng chỉ.
Khi Certbot đã tạo thành công chứng chỉ, khối máy chủ tạm thời được thêm vào trong bước 3 ở trên có thể bị xóa và bỏ ghi chú hai khối máy chủ khác. Sau khi thay đổi cấu hình, proxy sẽ cần được tải lại bằng một docker-compose down && docker-compose up -d
.
Thực hiện kiểm tra nhanh với docker ps -a
sẽ hiển thị một cái gì đó dọc theo các dòng sau:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
62b3a673f1cb nginx-proxy:0.0.2 "nginx -g 'daemon ..." 3 days ago Up 2 minutes 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp nginx-proxy
ea4acq9cc868 nginx:latest "nginx -g 'daemon ..." 4 days ago Up 3 minutes 0.0.0.0:8081->80/tcp nginx-wordpress
c7badc76c834 wordpress-prod:4.8.1-php5.6-fpm "docker-entrypoint..." 4 days ago Up 3 minutes 0.0.0.0:8082->9000/tcp wp
2ba321f4afdd mariadb "docker-entrypoint..." 4 days ago Up 3 minutes 0.0.0.0:8083->3306/tcp mysql
Nếu mọi thứ đều ổn, điều hướng đến https://example.com/wp-admin
sẽ hiển thị màn hình thiết lập WordPress tốt.