运行环境:Ubuntu 18.04 LTS以及Docker。
使用的软件为:
- MySQL,作为数据库;
- WordPress,本体;
- Nginx,网页服务器;
- Certbot,用于申请Let‘s Encrypt的证书。
以上程序都使用Docker镜像,由于完整的WordPress镜像里内置了Apache,这里使用适用于Nginx的WordPress-fpm镜像
主机使用的是AWS Lightsail 5刀的订阅,最低3.5刀的订阅内存只有512M似乎不够运行这一套东西。
准备
- 运行Ubuntu 18.04 LTS的服务器,其他系统流程一般应该是大同小异的;
- 一个域名,如果需要的话在最后有NameSilo的推广链接。此外,谷歌也能找到一些免费的域名提供商;
- 设置域名的A记录到服务器的IP地址,AWS不提供IPv6地址,所以也没法测试IPv6应该怎么做;
- 最后,记得打开服务器防火墙上的80和443端口。
安装Docker
这里参照Docker官网的安装说明进行安装,区别是apt-get被我改成了apt,不过没啥区别。如果安装过旧版的Docker要先更新,或者干脆卸载重装。我的机器里没有Docker,所以就直接安装了。
设置Docker仓库
更新软件源列表:
sudo apt update
安装一些依赖项,用于通过HTTPS获取软件仓库:
sudo apt install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
添加Docker的GPG密钥:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
搜索一下密钥的指纹来,检查一下密钥是否添加成功:
sudo apt-key fingerprint 0EBFCD88
如果添加成功的话会返回如下内容:
pub rsa4096 2017-02-22 [SCEA]
9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88
uid [ unknown] Docker Release (CE deb) <[email protected]>
sub rsa4096 2017-02-22 [S]
安装Docker EC
更新软件源:
sudo apt update
安装Docker EC和containerd,我这里直接安装最新版的:
sudo apt install docker-ce docker-ce-cli containers.io
测试是否安装成功:
sudo docker run hello-world
如果安装成功的话会输出一些有关Docker的说明之类的东西。
默认情况下,需要使用sudo命令来运行Docker,不过可以将用户添加到docker用户组来设置为Docker管理员,这样就不需要使用sudo了:
sudo usermod -aG docker your-user
其中 your-user为要使用docker的用户名。
现在Docker已经安装好了,不过为了方便使用这里使用Docker官方提供的容器编排工具Docker Compose来配置容器。
安装Docker Compose
下载Docker Compose:
sudo curl -L "https://github.com/docker/compose/releases/download/1.25.3/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
添加执行权限:
sudo chmod +x /usr/local/bin/docker-compose
测试是否安装成功:
docker-compose --version
如果输出版本号说明安装成功。
编写配置文件
首先建立一个文件夹用来保存所需的配置文件,例如wordpress文件夹:
mkdir wordpress && cd wordpress
编写Nginx配置文件
这里创建的Nginx配置文件用于使Certbot获取证书。如果不需要HTTPS的话也可以直接用,不过HTTPS是现在的趋势,建议还是用上比较好。
创建一个用来保存nginx配置文件的文件夹:
mkdir nginx-conf
编写nginx的配置文件,可以把vim换成顺手的编辑器,例如nano:
vim nginx-conf/nginx.conf
把下面的配置文件粘贴到编辑器里,然后把里面的example.com更换成要使用的域名:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
index index.php index.html index.htm;
root /var/www/html;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
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;
}
location ~ /\.ht {
deny all;
}
location = /favicon.ico {
log_not_found off; access_log off;
}
location = /robots.txt {
log_not_found off; access_log off; allow all;
}
location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
expires max;
log_not_found off;
}
}
最后记得保存
配置环境变量
这一步主要是为了将数据库的密码与docker compose文件分开保存,如果不做的话需要把密码写在docker compose文件内。
创建一个.env文件:
vim .env
在里面写入数据库密码,其中:
- your_root_password是root用户密码;
- your_wordpress_database_user是创建的用户名;
- your_wordpress_database_password是用户密码。
上面三个内容替换为自己要设置的用户名和密码
MYSQL_ROOT_PASSWORD=your_root_password
MYSQL_USER=your_wordpress_database_user
MYSQL_PASSWORD=your_wordpress_database_password
编辑完成后保存并关闭文件。
为了避免.env文件被存储到Git和Docker中,可以创建两个文件,先创建.dockerignore:
vim .dockerignore
然后输入不想保存的文件名:
.env
.git
docker-compose.yml
.dockerignore
然后保存。
同样,建立.gitignore文件:
vim .gitignore
输入:
.env
并保存。
创建Docker Compose配置文件
创建一个docker-compose.yml文件来为容器进行配置:
vim docker-compose.yml
首先写入Compose文件版本号,版本号适配的版本可以在Docker的官方文档里查询到,写这篇文章时的最新版是3:
version: '3'
接下来在下面配置数据库:
services:
db:
image: mysql
container_name: db
volumes:
- dbdata:/var/lib/mysql
restart: unless-stopped
env_file: .env
environment:
- MYSQL_DATABASE=wordpress
command: '--default-authentication-plugin=mysql_native_password'
networks:
- app-network
其中参数对应如下:
- image:使用的容器镜像,这里使用mysql镜像,可以在镜像名后面输入“:版本号”来指定使用的版本;
- container_name:容器的名称;
- restart:容器的重启策略,默认不会自动重启,这里设置为除非手动关闭,否则自动重启;
- env_file:将文件加入到环境变量中,这里就是之前创建的.env文件;
- environment:添加的环境变量,由于数据库名称不涉及到敏感信息,所以可以直接在这里添加;
- command:替换启动指令,因为使用的WordPress镜像不支持新版MySQL验证,使用这个选项来使MySQL使用旧版的身份验证。
继续在文件中配置wordpress:
wordpress:
depends_on:
- db
image: wordpress:fpm
container_name: wordpress
restart: unless-stopped
env_file: .env
environment:
- WORDPRESS_DB_HOST=db:3306
- WORDPRESS_DB_NAME=wordpress
- WORDPRESS_DB_USER=$MYSQL_USER
- WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
volumes:
- wordpress:/var/www/html
networks:
- app-network
其中:
- depends_on:用于设置容器的启动顺序,这里设置为使这个容器在数据库启动之后启动;
- image:由于使用Nginx作为网页服务器,所以这里使用Wordpress的fpm镜像;
- env_file:将.env文件作为环境变量;
- environment:设置数据库的端口,数据库名称,用户名和密码,其中端口号使用默认的3306端口,用户名和密码则通过.env文件来指定;
- volumes:将wordpress的数据卷挂载到/var/www/html目录下,以便与其他容器共享;
- networks:将容器添加到app-network网络中。
然后在文件中继续添加Nginx的配置:
webserver:
depends_on:
- wordpress
image: nginx
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- wordpress:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- app-network
其中选项对应为:
- ports:暴露的端口,这里使用HTTP默认使用的80端口和HTTPS默认使用的443端口;
- vloumes:这里分别挂载了数据卷和本机的数据文件
- wordpress:/var/www/html:将wordpress数据卷挂载到/var/www/html目录,这个是Nginx的根目录;
- ./nginx-conf:/etc/nginx/conf.d:将主机上的配置文件挂载到容器中的相应目录;
- certbot-etc:/etc/letsencrypt:将HTTPS需要的证书挂载到相应目录中。
最后,添加获取HTTPS证书的Certbot的配置:
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- wordpress:/var/www/html
command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --staging -d example.com
其中,command选项中的参数里的[email protected]为申请证书所使用的邮箱,example.com为要申请的域名。
- --webroot:使用webroot插件来进行HTTP-01验证;
- --webroot-path:指定webroot目录的路径;
- --email:注册和恢复证书使用的电子邮件,在这里使用的例子为[email protected],应换成要使用的电子邮件;
- --agree-tos:表示同意ACME的使用协议;
- --no-eff-email:表示不与电子前哨基金会共享电子邮件地址,如果愿意共享的话可以删除;
- --staging:使用测试模式来获取证书,因为每周申请证书的次数是有限的,可以加上这个参数进行测试,确认运行正常之后再删除该参数来正式申请证书;
- -d: 指定申请证书的域名,这里的例子是example.com,应换成要使用的域名。
最后,在文件中添加如下内容来定义数据卷和网络:
volumes:
certbot-etc:
wordpress:
dbdata:
networks:
app-network:
driver: bridge
其中volumes用于定义数据卷,可用于在容器之间共享文件,networks可以定义容器之间的通信网络,使容器之间可以互相通信。
最后完成的docker-compose.yml文件应如下:
version: '3'
services:
db:
image: mysql
container_name: db
volumes:
- dbdata:/var/lib/mysql
restart: unless-stopped
env_file: .env
environment:
- MYSQL_DATABASE=wordpress
command: '--default-authentication-plugin=mysql_native_password'
networks:
- app-network
wordpress:
depends_on:
- db
image: wordpress:fpm
container_name: wordpress
restart: unless-stopped
env_file: .env
environment:
- WORDPRESS_DB_HOST=db:3306
- WORDPRESS_DB_NAME=wordpress
- WORDPRESS_DB_USER=$MYSQL_USER
- WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
volumes:
- wordpress:/var/www/html
networks:
- app-network
webserver:
depends_on:
- wordpress
image: nginx
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- wordpress:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- app-network
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- wordpress:/var/www/html
command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --staging -d example.com
volumes:
certbot-etc:
wordpress:
dbdata:
networks:
app-network:
driver: bridge
运行容器
在docker-compose.yml文件所在的文件夹内,执行如下命令来运行容器:
docker-compose up -d
如果配置正确的话,可以看到输出以下信息:
Creating db ... done
Creating wordpress ... done
Creating webserver ... done
Creating certbot ... done
使用docker-compose ps来查看docker运行状态:
docker-compose ps
如果运行正常的话会返回如下结果:
Name Command State Ports
-------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
db docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp
webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcp
wordpress docker-entrypoint.sh php-fpm Up 9000/tcp
如果db wordpress webserver的State列不是中的状态不是Up或者certbot的退出状态不是0的话,可以使用下列命令来查看日志:
docker-compose logs service_name
其中service_name为要查看的容器名称。
接下来,可以使用下列命令来查看证书是否安装成功:
docker-compose exec webserver ls -la /etc/letsencrypt/live
如果证书申请成功的话会看到以下内容:
total 16
drwx------ 3 root root 4096 May 10 15:45 .
drwxr-xr-x 9 root root 4096 May 10 15:45 ..
-rw-r--r-- 1 root root 740 May 10 15:45 README
drwxr-xr-x 2 root root 4096 May 10 15:45 example.com
这说明证书申请成功,现在应该编辑docker-compose.yml文件,将certbot的command选项里面的--staging替换为--force-renewal,替换之后应如下所示:
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- wordpress:/var/www/html
command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --force-renewal -d example.com
接下来重新运行certbot:
docker-compose up --force-recreate --no-deps certbot
如果输出如下内容,说明证书申请成功:
Recreating certbot ... done
Attaching to certbot
certbot | Saving debug log to /var/log/letsencrypt/letsencrypt.log
certbot | Plugins selected: Authenticator webroot, Installer None
certbot | Renewing an existing certificate
certbot | Performing the following challenges:
certbot | http-01 challenge for example.com
certbot | http-01 challenge for www.example.com
certbot | Using the webroot path /var/www/html for all unmatched domains.
certbot | Waiting for verification...
certbot | Cleaning up challenges
certbot | IMPORTANT NOTES:
certbot | - Congratulations! Your certificate and chain have been saved at:
certbot | /etc/letsencrypt/live/example.com/fullchain.pem
certbot | Your key file has been saved at:
certbot | /etc/letsencrypt/live/example.com/privkey.pem
certbot | Your cert will expire on 2019-08-08. To obtain a new or tweaked
certbot | version of this certificate in the future, simply run certbot
certbot | again. To non-interactively renew *all* of your certificates, run
certbot | "certbot renew"
certbot | - Your account credentials have been saved in your Certbot
certbot | configuration directory at /etc/letsencrypt. You should make a
certbot | secure backup of this folder now. This configuration directory will
certbot | also contain certificates and private keys obtained by Certbot so
certbot | making regular backups of this folder is ideal.
certbot | - If you like Certbot, please consider supporting our work by:
certbot |
certbot | Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
certbot | Donating to EFF: https://eff.org/donate-le
certbot |
certbot exited with code 0
修改Web服务器来开启HTTPS
首先应先停止Nginx服务:
docker-compose stop webserver
使用curl来下载Certbot推荐的Nginx参数:
curl -sSLo nginx-conf/options-ssl-nginx.conf https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf
以上命令会在nginx-conf文件夹中创建一个文件名为options-ssl-nginx.conf文件。
接下来编辑nginx.conf文件:
vim nginx.conf
将文件内容替换为如下内容:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
location / {
rewrite ^ https://$host$request_uri? permanent;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
index index.php index.html index.htm;
root /var/www/html;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/nginx/conf.d/options-ssl-nginx.conf;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# enable strict transport security only if you understand the implications
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
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;
}
location ~ /\.ht {
deny all;
}
location = /favicon.ico {
log_not_found off; access_log off;
}
location = /robots.txt {
log_not_found off; access_log off; allow all;
}
location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
expires max;
log_not_found off;
}
}
和之前一样,将example.com替换为要使用的域名。
编辑完成之后保存文件,并重新运行webserver容器:
docker-compose up -d --force-recreate --no-deps webserver
再次使用docker-compose ps命令来检查容器运行状态:
docker-compose ps
正常情况下会返回如下内容:
Name Command State Ports
-----------------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
db docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp
webserver nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
wordpress docker-entrypoint.sh php-fpm Up 9000/tcp
安装wordPress
现在,使用浏览器访问设置好的域名,就可以看到WordPress的安装界面。
首先在安装界面内选择要使用的语言,然后点击继续。
接下来需要输入网站的名称,用户名和密码以及电子邮件,也可以使用WordPress自动生成的强密码。最后还可以选择是否让搜索引擎来搜索这个网站。都设置完成后点击安装,安装完成之后会提示进行登录。
登录完成之后,WordPress就安装完毕。
设置证书自动更新
因为之前使用的Let‘s Encrypt证书的有效期只有90天,所以需要为设置自动更新来确保证书不会失效。
用cron可以定期运行脚本来使Certbot定期更新Let‘s Encrypt证书。
创建一个脚本:
vim ssl_renew.sh
在里面写入如下内容:
#!/bin/bash
COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"
cd /home/user/wordpress/
$COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af
这个脚本可以通过docker-compose来使certbot更新证书并重新加载nginx的配置。其中/home/user/wordpress/是存放配置文件的文件夹,应更换为实际存放的位置。--dry-run参数则是用于测试更新过程。
编辑完成后保存,然后为脚本增加执行权限:
chmod +x ssl_renew.sh
完成之后使用crontab来使脚本重复运行:
sudo crontab -e
如果第一次使用的话会出现选择编辑的界面,选择最顺手的就可以:
no crontab for root - using an empty one
Select an editor. To change later, run 'select-editor'.
1. /bin/nano <---- easiest
2. /usr/bin/vim.basic
3. /usr/bin/vim.tiny
4. /bin/ed
Choose 1-4 [1]:
进入编辑器后,在文件最后添加以下内容:
*/5 * * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
其中最开始的*/5 * * * *为执行时间的设置,从左到右分别为分钟,小时,日期,月份,星期。其中符号含义如下
- *:表示所有可能的值;
- , :用逗号隔开的值表示列表范围,如“1,3,5,7”;
- -:横线表示范围,如2-6;
- /:表示间隔频率,可以和*同时使用如2-8/2或*/2
后面为要执行的命令,这里表示为每5分钟执行一次命令。
等待5分钟后,检查一下/var/log/cron.log文件来验证更新是否成功:
tail -f /var/log/cron.log
如果输出如下内容,说明更新成功:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates below have not been saved.)
Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/example.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
成功之后重新设置自动更新的间隔,如每月1日自动检查更新:
0 0 1 * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
之后编辑自动更新脚本,删除其中的测试选项--dry-run:
#!/bin/bash
COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"
cd /home/sammy/wordpress/
$COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af
到这里,WordPress就正式安装完成了。
参考
How To Install WordPress With Docker Compose
NameSilo推广链接:
Comments NOTHING