博客从 Ubuntu14.0 迁移到 Ubuntu24.0 流程
一、迁移目的
博客是 10年前用PHP7.0(laraval框架)在阿里云上搭建的,服务器配置 1C 2G 30G,每年 750元,费用很贵,对老用户一点优惠也没有,另外Ubuntu14.0 系统太老,许多安装包都无法兼容,年久失修,php7.0 目前已经找不到环境了,只能用Docker来做,所以,痛下决心,进行升级换代,并改为Docker方式部署,
二、迁移步骤
使用 Docker 进行构建应用服务和相关组件;
root@dev-server:~# cd /var/www/
root@dev-server:/var/www# ls -l
total 24
-rw-r--r-- 1 root root 1129 Nov 13 17:56 docker-compose.yml
-rw-r--r-- 1 root root 236 Nov 13 17:55 Dockerfile
-rw-r--r-- 1 root root 236 Nov 13 17:54 Dockerfile-php78
-rw-r--r-- 1 root root 461 Nov 13 17:59 nginx.conf
-rw-r--r-- 1 root root 140 Nov 13 16:02 php.ini
drwxr-xr-x 15 root www-data 4096 Nov 13 16:28 road2chain
root@dev-server:/var/www#
docker-compose.yml 文件:
version: '3.8'
services:
php:
build: .
image: myphp:7.0-fpm-pdo_mysql
container_name: php7-fpm
restart: always
volumes:
- ./road2chain:/var/www/html
- ./php.ini:/usr/local/etc/php/php.ini
working_dir: /var/www/html
networks:
- backend
nginx:
image: nginx:1.21
container_name: nginx-php7
restart: always
ports:
- "80:80"
volumes:
- ./road2chain:/var/www/html
- ./nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
networks:
- backend
mysql:
image: mysql:5.7
container_name: mysql57
restart: always
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: xxxxxxx
MYSQL_DATABASE: road2chain
volumes:
- /data/mysql57/conf/mysqld.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf
- /data/mysql57/data:/var/lib/mysql
- /data/mysql57/logs:/var/log/mysql
networks:
- backend
redis:
image: redis:5.0
container_name: redis5
ports:
- "6379:6379"
restart: always
networks:
- backend
networks:
backend:
driver: bridge
Dockerflie 文件(主要用来构建 mysql-pdo扩展到 php7.0-fpm 镜像)
root@dev-server:/var/www# cat Dockerfile
# 使用官方 PHP 7.0 FPM 镜像, 只能是 php7.0, 如果过高的版本 如 php7.4 就会出现语法报错;
FROM php:7.0-fpm
# 安装 MySQL PDO 扩展
RUN docker-php-ext-install pdo_mysql
# 可选:拷贝自定义 php.ini
COPY php.ini /usr/local/etc/php/php.ini
# 设置工作目录
WORKDIR /var/www/html
nginx.conf 文件
root@dev-server:/var/www# cat nginx.conf
server {
listen 80;
server_name digtime.cn www.digtime.cn;
root /var/www/html/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass php:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
}
location ~ /\.ht {
deny all;
}
}
php.ini 文件:
root@dev-server:/var/www# cat php.ini
date.timezone = Asia/Shanghai
memory_limit = 512M
upload_max_filesize = 50M
post_max_size = 50M
display_errors = On
error_reporting = E_ALL
构建镜像命令
# 构建含有 pdo-mysql 的php7.0 镜像,只能是 php7.0, 如果过高的版本 如 php7.8 就会出现语法报错;
docker compose build php
启动服务
cd /var/www
# 启动
docker compose up -d
# 停止
docker compose down
进程:
root@dev-server:/var/www# sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9bbf84c4bd30 nginx:1.21 "/docker-entrypoint.…" 2 months ago Up 2 months 0.0.0.0:80->80/tcp, [::]:80->80/tcp nginx-php7
b3f5a71a2c5e myphp:7.0-fpm-pdo_mysql "docker-php-entrypoi…" 2 months ago Up 2 months 9000/tcp php7-fpm
760d929f129b redis:5.0 "docker-entrypoint.s…" 2 months ago Up 2 months 6379/tcp redis5
d94e0db6f948 mysql:5.7 "docker-entrypoint.s…" 2 months ago Up 2 months 0.0.0.0:3306->3306/tcp, [::]:3306->3306 /tcp, 33060/tcp mysql57
添加SSL 访问
问题
我觉得上边的技术方案有问题,改动比较大,希望将 certbot ssl生成放在宿主机部署,宿主机定时更新证书,然后再宿主机部署一个前置的 nginx (80,433),然后再代理到后端的博客服务 docker 容器 80 上去,这样是否更好一些?应为生成 certbot 证书需要80端口服务可以访问得通,这样也避免出现上边的问题,请给出建议和实操方案。
下边是目录:
root@dev-server:/var/www# ls -l
total 36
drwxr-xr-x 2 root root 4096 Feb 4 17:28 backup-20260204
drwxr-xr-x 4 root root 4096 Feb 4 17:28 certbot
-rw-r--r-- 1 root root 1391 Feb 4 17:40 docker-compose-bak-0204.yml
-rw-r--r-- 1 root root 1131 Feb 4 17:49 docker-compose.yml
-rw-r--r-- 1 root root 983 Nov 17 22:24 Dockerfile
-rw-r--r-- 1 root root 236 Nov 13 17:54 Dockerfile-php78
-rw-r--r-- 1 root root 943 Feb 4 17:53 nginx.conf
-rw-r--r-- 1 root root 140 Nov 13 16:02 php.ini
drwxr-xr-x 15 root www-data 4096 Nov 15 08:27 road2chain
你的这个思路其实是 更稳、更工程化、生产中更常见的方案 👍
而且对于你这种:
- 老 PHP7 项目
- Docker 已运行稳定
- 只想补 HTTPS
- 不想频繁改 docker 配置
- 未来可能多站点
👉 宿主机前置 Nginx + 宿主机 Certbot
确实是企业最常用架构。
你这个方向是 对的,而且更推荐。
⭐ 推荐最终架构
Internet
│
▼
宿主机 Nginx (80 / 443 + SSL + 证书续期)
│
▼
Docker nginx (内部80端口)
│
▼
PHP-FPM
👍 这个方案优势
✔ Certbot 永远能占用 80
不会和 docker 争抢端口
✔ Docker 容器零改动
你博客不用动
✔ 后期多站点极容易扩展
一台服务器多个域名统一管理
✔ 生产环境标准反向代理架构
大公司基本都这么做
🚀 实操方案(非常稳)
我给你一套 可直接上线版本
一、修改 Docker 架构(只改一个地方)
让 docker nginx 不再暴露 80 给公网。
修改 docker-compose.yml
原来
ports:
- "80:80"
改成 👇
ports:
- "127.0.0.1:8080:80"
👉 只允许宿主机访问
👍 修改后的 nginx docker 访问方式
宿主机访问:
http://127.0.0.1:8080
二、重启 docker
docker-compose down
docker-compose up -d
三、宿主机安装 nginx
如果没装:
apt update
apt install nginx -y
四、宿主机安装 certbot
apt install certbot python3-certbot-nginx -y
五、配置宿主机 nginx 反向代理
新建配置
nano /etc/nginx/sites-available/digtime.cn
写入
server {
listen 80;
server_name digtime.cn www.digtime.cn;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
启用站点
ln -s /etc/nginx/sites-available/digtime.cn /etc/nginx/sites-enabled/
测试 nginx
nginx -t
systemctl reload nginx
六、申请证书(超级简单)
现在 certbot 可以直接帮你自动改 nginx。
执行:
certbot --nginx -d digtime.cn -d www.digtime.cn
certbot 会:
- 自动生成证书
- 自动写 HTTPS 配置
- 自动配置跳转
- 自动注册续期
七、自动续期(基本已经帮你做好)
certbot 安装后自带:
systemctl list-timers | grep certbot
如果你想手动确认:
certbot renew --dry-run
⭐ 最终宿主机 nginx 会自动变成类似:
server {
listen 80;
server_name digtime.cn www.digtime.cn;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/digtime.cn/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/digtime.cn/privkey.pem;
server_name digtime.cn www.digtime.cn;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
👍 架构变成
公网
↓
宿主 nginx SSL
↓
docker nginx
↓
php-fpm
⭐ 这是当前互联网最常见结构
包括:
- k8s ingress
- 云 WAF
- CDN 边缘代理
都是类似层级。
⚠️ 你这个方案唯一注意
要保留 Host 头
proxy_set_header Host $host;
否则很多 PHP 程序会出错。
⭐ 额外建议(非常推荐)
在 docker nginx 增加:
real_ip_header X-Forwarded-For;
这样日志记录真实 IP。
👍 这个方案还有隐藏好处
你未来如果接:
- Cloudflare
- 阿里云 CDN
- WAF
完全不用改 docker。
⭐ 性能也更好
SSL 终止在宿主机,减少容器负担。
👍 你的问题本质其实是
Certbot 必须占用 80 验证。
你把 80 留给 docker,就会冲突。
⭐ 你的新方案是行业推荐做法
非常正确 👍
上传图片 nginx 大小限制调整
php nginx 的配置:
root@dev-server:/var/www# cat nginx.conf
server {
listen 80;
server_name digtime.cn www.digtime.cn;
root /var/www/html/public;
index index.php index.html;
# real ip
real_ip_header X-Forwarded-For;
##
# Basic Settings
##
client_max_body_size 20m;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
#include /etc/nginx/mime.types;
#default_type application/octet-stream;
##
# Logging Settings
##
#access_log /var/log/nginx/access.log;
#error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
#gzip on;
#gzip_disable "msie6";
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass php:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
# --- 新增下面这一行 ---
# 把宿主机传来的 X-Forwarded-Proto 传给 PHP
fastcgi_param HTTP_X_FORWARDED_PROTO $http_x_forwarded_proto;
}
location ~ /\.ht {
deny all;
}
}
root@dev-server:/var/www# ls -l
宿主机Nginx 文件大小配置调整,这里在全局 /etc/nginx/nginx.conf 进行调整,这样所有的子配置 /etc/nginx/sites-available/digtime.cn 也都可以使用:
cd /etc/nginx/
root@dev-server:/etc/nginx# vim nginx.conf
---
root@dev-server:/etc/nginx# cat nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
tcp_nodelay on;
client_max_body_size 20m; # 新增
# 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 TLSv1.3; # 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_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/*;
}
#mail {
# # See sample authentication script at:
# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
#
# # auth_http localhost/auth.php;
# # pop3_capabilities "TOP" "USER";
# # imap_capabilities "IMAP4rev1" "UIDPLUS";
#
# server {
# listen localhost:110;
# protocol pop3;
# proxy on;
# }
#
# server {
# listen localhost:143;
# protocol imap;
# proxy on;
# }
#}
修改完成后,重启宿主机的nginx:
nginx -t
systemctl reload nginx
然后,重新测试上传图片,上传图片成功!
为者常成,行者常至
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)