建站笔记
0. 前言
从2025年10月租了云服务器开始,陆陆续续搭建了一个自己的网站,一路上踩了很多坑,不过也干了很多事,包括域名备案、各种docker安装、nginx反向代理、wordpress设置、ssl证书,最后网站摇摇欲坠地运行起来了。记录一下整个过程中遇到的问题,假装自己以后还会来翻看。
1. 域名备案
在阿里云上买了个域名,实名认证以后就可以进行ICP备案了。这一步没什么好说的,就是命名啊这些比较麻烦,可以全程自己操作,不用买阿里云的付费服务。参考互联网信息服务备案办理维护-备案-阿里云即可。将域名绑定到云服务器上,就可以实现域名解析到云服务器的公网IP,然后就可以通过域名去访问云服务器上的网页等服务了。
2. WordPress安装
参考自:WordPress 云服务器 Docker 部署保姆级教程 – albert-1024 – 博客园
我是通过docker在云服务器上部署的WordPress,还是挺简单的。docker镜像源可以用轩辕镜像 – Docker 镜像高效稳定拉取服务,我充了个会员可以直接下。不过我的云服务器上的WordPress不是从这里下载的,我也忘了是从哪里下的了,我下的是apache版的,关于apache和nginx版的区别,可以看对于 WordPress 而言, Nginx 与 Apache 谁更合适呢? – 站长帮。除了WordPress以外,还需要部署一个mysql的docker,用来存WordPress的一些配置、数据等。
下好docker镜像后,依次启动mysql、WordPress容器,都使用了挂载卷将宿主机的目录挂载到容器内部,可以将容器运行时产生的数据持久化存储起来,即使容器被删除或者重新创建,数据也不会丢失,仍然存在于宿主机的目录下:
注意,如果不想docker network创建一个桥接网络,直接启动mysql容器的话,系统会自动分配容器内部IP(可以通过docker inspect查看),这样会导致如果服务器重启的话,mysql地址会变,wordpress连接数据库就会报错。因此我将mysql容器指定了桥接网络和固定IP:
docker run -d \
--name mysql \
-v /home/path to mysql data:/var/lib/mysql \
-v /home/path to mysql conf:/etc/mysql/conf.d \
-v /home/path to mysql logs:/var/log/mysql \
--network ***-network \
--ip 172.******* \
-p port of mysql of outside:3306 \
-e MYSQL_ROOT_PASSWORD=密码 \
--restart unless-stopped \
mysql-server:8.0.32
# 启动mysql容器后,还需要配置数据库和mysql能够被外部访问,如果没有这一步的话,wordpress连接不上数据库
docker exec -it mysql /bin/bash
mysql -u root -p
create database wordpress;
# 由于 MySQL 8.0+ 不允许通过 GRANT 语句隐式创建用户。需要先显式创建用户,再授予权限。
-- 1. 先登录 MySQL(使用已有 root@localhost 账号)
mysql -u root -p
-- 2. 创建远程 root 用户
CREATE USER 'root'@'%' IDENTIFIED BY 'StrongPassword123!';
-- 3. 授予权限
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
-- 4. 刷新
FLUSH PRIVILEGES;
-- 5. 验证
SELECT user, host FROM mysql.user WHERE user = 'root';
然后,启动wordpress容器,并指定其桥接网络和固定IP,以实现和mysql容器直接的内部通信:
docker run -d \
--name wordpress \
-p port of wordpress of outside:80 \
-v /path to /www/html:/var/www/html \
--network ***-network \
--ip 172.****** \
--restart unless-stopped \
wordpress:php8.4-apache
这里说明一下,容器的 --ip 参数和外部访问是两个独立的概念:
| 参数 | 作用范围 | 用途 |
|---|---|---|
--ip 172.20.0.20 | 容器内部网络 | 容器间通信,其他容器通过此 IP 访问 |
-p 80:80 | 宿主机 ↔ 容器 | 外部通过宿主机 IP + 端口访问容器 |
| 问题 | 答案 |
|---|---|
配置了 --ip 后,外部还能访问吗? | 能,只要配置了 -p 端口映射 |
--ip 的作用是什么? | 容器在内部网络的固定地址,用于容器间通信 |
| 外部访问靠什么? | -p 端口映射,与 --ip 无关 |
| 访问地址是什么? | http://<云服务器公网IP>:<宿主机端口> |
💡 一句话记住:--ip 是给容器之间用的,-p 是给外部访问用的,两者互不冲突!
至此,如果直接打开域名:wordpress端口,则会进入到设置界面,填上数据库的信息,就差不多装好了,后面就是wordpress装主题啊设置啊这些了,就不用记录了。对于头像不能正常加载的问题,可以装一个WPAvatar插件。
3. Nginx反向代理和ssl配置
由于我的服务器上还运行了其他web服务,各自在不同的端口,我希望能够通过域名/子页面的形式去访问它们,而不是域名:端口的形式,因此需要使用反向代理,这里是采用了Nginx来作反向代理,同时还安装和配置了自动续签Let’s Encrypt免费证书,实现https访问。
3.1 SSL证书配置
参考自:阿里云服务器如何安装和续签Let’s Encrypt免费证书
Let’s Encrypt 是一个免费的、自动化的、开放的证书颁发机构(CA),旨在通过提供免费的SSL/TLS证书来提高整个互联网的安全性。
首先需要安装安装Certbot。Certbot 是 EFF 开发的一个自动化客户端工具,用于从 Let’s Encrypt 获取和安装证书。我们需要使用yum命令来安装Certbot及其相关组件。
添加EPEL仓库:
sudo yum install epel-release -y
# 如果上述命令安装报错,可先卸载epel-aliyuncs-release再重新安装
sudo yum remove epel-aliyuncs-release -y
sudo yum install epel-release -y
安装Certbot和Nginx插件:
sudo yum install certbot python3-certbot-nginx -y
安装完Certbot后,可以通过以下命令为所有二级域名统一签发证书:
sudo certbot certonly --manual --preferred-challenges dns -d *.example.com -d example.com
操作完成之后,系统会生成一个txt记录,需要记录到dns服务器上。到阿里云云解析DNS中找到当前域名,添加一个txt记录,把上图中出现的记录值记录进去。添加后可以通过记录旁边的生效检测进行拨测,看解析值是否就是填入的值。
Certbot完成后,SSL证书和密钥文件通常会存储在/etc/letsencrypt/live/域名/目录中。
3.2 自动续签SSL证书
续签测试:
sudo certbot renew --dry-run
不过会报错,因为Certbot是通过DNS方式申请域名证书,因此在续订时需要更新 DNS 的TXT记录,需要有权限去修改阿里云DNS设置,所以直接使用 certbot renew 更新会报错。我们可以使用certbot-dns-aliyun:https://github.com/justjavac/certbot-dns-aliyun,该脚本能够自动调用阿里云接口,实现自动申请和续签证书。
首先,需要安装阿里云cli工具:
wget https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz
tar xzvf aliyun-cli-linux-latest-amd64.tgz
sudo cp aliyun /usr/local/bin
rm -rf aliyun
然后,登录 https://ram.console.aliyun.com/ RAM访问控制,在用户中创建新用户,勾选访问配置中的“使用永久AccessKey 访问”,来创建 AccessKey ID和AccessKey Secret,用于API 或其他开发工具访问。完成后记录AccessKeyID 和 AccessKeySecret,并添加AliyunDNSFullAccess 授权。
回到服务器执行如下代码:
sudo aliyun configure
Access Key Id []: AccessKeyID
Access Key Secret []: AccessKeySecret
Default Region Id []: cn-chengdu
Default Output Format [json]: json (Only support json)
Default Language [zh|en] en: zh
接下来通过脚本安装cerbot-dns-aliyun:
git clone https://github.com/justjavac/certbot-dns-aliyun
sudo cp alidns.sh /usr/local/bin
sudo chmod +x /usr/local/bin/alidns.sh
sudo ln -s /usr/local/bin/alidns.sh /usr/local/bin/alidns
至此,就可以进行续签测试了:
# 测试申请
certbot certonly -d *.example.com --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean" --dry-run
# 续签测试
certbot renew --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean" --dry-run
正式续签只需要去掉 –dry-run参数即可。
最后通过crontab设置定时任务实现在每月的1号的凌晨2点0分执行一次,使用手动模式进行证书续签,续签成功后重新加载Nginx,以应用新的证书:
sudo crontab -e
0 2 1 */1 * certbot renew --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean" --deploy-hook "docker restart nginx"
3.3 Nginx反向代理
这一部分我是用大模型生成的Nginx配置文件。首先创建了nginx-proxy文件夹,并在里面创建了logs文件夹和nginx.conf,配置文件可以由大模型生成,这里就不贴出来了,重点在于监听80端口对http请求进行重定向为https请求,然后配置好ssl相关参数,配置好url和对应的转发端口。由于有些网页后端容器监听的是http服务,所以SSL终止在nginx层,proxy_pass为http://域名:端口,如果proxy_pass配置成了https,则会502,这是因为
用户浏览器
↓ (HTTPS - 加密)
Nginx 反向代理容器 (443端口)
↓ (HTTP - 内部)
后端容器 (WordPress/QuickRef/Gitea 等)
┌─────────────────────────────────────────────────┐
│ 外部网络 (加密) │
│ 浏览器 ←→ HTTPS ←→ Nginx (443) │
└─────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────┐
│ 内部网络 (无需加密) │
│ Nginx → HTTP → 后端容器 (80/3000) │
└─────────────────────────────────────────────────┘
我将wordpress主页配置为根路径,即通过域名可以直接访问wordpress,本来想通过域名/blog来访问的,但是wordpress的管理页面会自动重定向为域名/wp-admin,导致404错误,实在是不知道怎么搞了,我就放弃了,改为域名直接访问。
然后需要将wordpress的wordpress地址和站点地址改为https://域名,这一步可以在服务器上改,也可以在网页上改。服务器中改的话,直接/www/html/wp-config.php中添加即可:
// 修复 HTTPS 重定向问题
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] = 'on';
}
// 设置正确的站点 URL(如果使用子目录)
define('WP_HOME', 'http://域名/');
define('WP_SITEURL', 'http://域名/');
// 强制管理后台使用 HTTPS
define('FORCE_SSL_ADMIN', true);
// 禁用文件编辑器(安全)
define('DISALLOW_FILE_EDIT', true);
不过把这两个地址改为http好像也没啥问题,因为nginx会转发为https,所以最终都是跳转为https。
3.4 部分网站配置修改
Gitea
我部署了Gitea,需要对其子路径代理进行配置,让Gitea 知道它运行在 /gitea/ 子路径下,生成正确的资源链接:docker exec gitea cat /data/gitea/conf/app.ini
Gitea需要在配置文件中配置 ROOT_URL以及在Nginx中配置 X-Script-Name 才能生成正确的资源路径。
WordPress
只是单纯的修改站点,还是会导致WordPress的样式资源文件加载错误:
/blog/wp-content/themes/pure-blog/js/base.js?ver=202403 net::ERR_ABORTED 404 (Not Found)
此时,需要对数据库中存储的 URL 进行同步修改:
# 进入 MySQL 容器
docker exec -it mysql mysql -uroot -p*********
# 选择 WordPress 数据库
USE wordpress;
# 检查当前的站点地址
SELECT option_name, option_value FROM wp_options
WHERE option_name IN ('siteurl', 'home');
# 更新为正确的 URL(关键!)
UPDATE wp_options SET option_value = 'https://域名/blog' WHERE option_name = 'siteurl';
UPDATE wp_options SET option_value = 'https://域名/blog' WHERE option_name = 'home';
# 退出
exit;