博客从 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

然后,重新测试上传图片,上传图片成功!

为者常成,行者常至