基于 Docker 搭建稳定安全的 Typecho 博客系统[cite: 1]

最近在一台 OVH VPS 上重新规划个人博客环境,希望搭建一个稳定、安全、方便扩展的 Docker 化博客系统[cite: 1]。

技术栈选型:

  • 操作系统:Debian[cite: 1]
  • 容器化:Docker / Docker Compose[cite: 1]
  • 反向代理:Nginx Proxy Manager[cite: 1]
  • 博客程序:Typecho[cite: 1]
  • 数据库:MariaDB[cite: 1]
  • 网络隔离:Docker 自定义网络[cite: 1]

本文记录整个搭建过程[cite: 1]。


一、服务器环境[cite: 1]

服务器配置[cite: 1]

  • CPU:Intel Core i7-7700K[cite: 1]
  • 内存:32GB[cite: 1]
  • 硬盘:双 SSD[cite: 1]
  • 带宽:1Gbps[cite: 1]
  • 系统:Debian[cite: 1]

服务器用途[cite: 1]

  • 个人博客[cite: 1]
  • 图床[cite: 1]
  • 邮件服务[cite: 1]
  • 其他 Web 服务[cite: 1]

因此整体采用服务隔离的 Docker 架构[cite: 1]。


二、整体架构[cite: 1]

拓扑结构[cite: 1]

            Internet
                |
             HTTPS 443
                |
    Nginx Proxy Manager (反向代理)
                |
         Docker proxy 网络
                |
          +-------------+
          |             |
      Typecho        其他服务
          |
    database 网络
          |
      MariaDB

设计原则[cite: 1]

  1. 只开放必要公网端口[cite: 1]。
  2. 应用服务不直接暴露至公网[cite: 1]。
  3. 数据库仅允许内部网络访问[cite: 1]。
  4. 全局使用 Docker 网络进行通信[cite: 1]。

三、创建 Docker 公共网络[cite: 1]

在部署容器前,需先手动创建一个独立的 Docker 公共网络,用于跨项目/容器间的通信[cite: 1]。

创建命令[cite: 1]

docker network create proxy

网络架构示意[cite: 1]

proxy (外部网络)
├── nginx-proxy-manager
└── typecho

作用与优势[cite: 1]

docker-compose.yml 中声明 external: true 意味着 Docker Compose 将直接使用已存在的 proxy 网络而不会重复创建[cite: 1]。这样一来,NPM 容器即可直接通过容器名访问同一网络内的 typecho:80[cite: 1]。


四、部署 Nginx Proxy Manager[cite: 1]

Nginx Proxy Manager (NPM) 主要负责:域名转发、HTTPS SSL 证书自动申请与续签、反向代理以及作为整个服务器的 Web 服务统一入口[cite: 1]。

  • 工作目录/opt/docker/nginx-proxy-manager[cite: 1]

docker-compose.yml 配置[cite: 1]

services:
  npm:
    image: jc21/nginx-proxy-manager:2.15.1
    container_name: nginx-proxy-manager
    restart: always
    ports:
      - "80:80"
      - "443:443"
      - "127.0.0.1:81:81"
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    networks:
      - proxy

networks:
  proxy:
    external: true

五、为什么关闭 81 端口公网访问?[cite: 1]

Nginx Proxy Manager 默认的端口绑定规则为 0.0.0.0:81,这意味着任何人都可以在公网上直接尝试访问管理后台[cite: 1]。

修改为 127.0.0.1:81:81 后的访问路径对比:

  • 公网访问公网X81 端口关闭[cite: 1]
  • 本机访问本机127.0.0.1:81NPM 管理后台[cite: 1]

远程管理方式[cite: 1]

如需从本地电脑安全访问管理后台,可使用 SSH 隧道进行端口转发:

ssh -L 8081:127.0.0.1:81 alice@服务器IP -p 22222

执行后,在本地浏览器打开 http://127.0.0.1:8081 即可安全进入 NPM 管理后台[cite: 1]。


六、部署 Typecho 与 MariaDB[cite: 1]

  • 博客镜像joyqi/typecho:1.3.0-php8.2-apache(集成 Typecho、Apache 和 PHP 8.2)[cite: 1]
  • 工作目录/opt/docker/typecho[cite: 1]

docker-compose.yml 配置[cite: 1]

services:
  mariadb:
    image: mariadb:11
    container_name: typecho-db
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: your_root_password
      MYSQL_DATABASE: typecho
      MYSQL_USER: typecho
      MYSQL_PASSWORD: your_password
    volumes:
      - ./mysql:/var/lib/mysql
    networks:
      - database

  typecho:
    image: joyqi/typecho:1.3.0-php8.2-apache
    container_name: typecho
    restart: always
    depends_on:
      - mariadb
    environment:
      TYPECHO_SITE_URL: [https://blog.example.com](https://blog.example.com)
      TYPECHO_DB_ADAPTER: Pdo_Mysql
      TYPECHO_DB_HOST: mariadb
      TYPECHO_DB_PORT: 3306
      TYPECHO_DB_USER: typecho
      TYPECHO_DB_PASSWORD: your_password
      TYPECHO_DB_DATABASE: typecho
    volumes:
      - ./typecho:/app/usr
    networks:
      - proxy
      - database

networks:
  proxy:
    external: true
  database:

七、为什么 Typecho 服务没有映射 ports?[cite: 1]

传统方式[cite: 1]

传统部署会配置 ports: - "8080:80",直接通过 http://服务器IP:8080 访问[cite: 1]。

当前架构[cite: 1]

在当前方案中,访问链路为:

用户 ➔ 端口 443 ➔ Nginx Proxy Manager ➔ Docker内部网络 (proxy) ➔ Typecho

因此 Typecho 容器完全不需要在宿主机映射任何端口,只需暴露在内网即可[cite: 1]。


八、MariaDB 数据库隔离[cite: 1]

MariaDB 容器仅加入 database 网络,不加入 proxy 网络[cite: 1]。

Typecho ──(database 网络)── MariaDB
  • 数据库未暴露到公网[cite: 1]。
  • 宿主机不需要开放 3306 端口,极大提高了数据安全性[cite: 1]。

九、服务启动与验证[cite: 1]

1. 检查与启动[cite: 1]

# 检查 Compose 配置语法
docker compose config

# 后台启动所有服务
docker compose up -d

# 查看正在运行的容器
docker ps

启动完成后,应能看到以下容器运行:

  • nginx-proxy-manager[cite: 1]
  • typecho[cite: 1]
  • typecho-db[cite: 1]

2. 测试 Docker 网络连通性[cite: 1]

进入 NPM 容器内部进行网络联通性测试:

docker exec -it nginx-proxy-manager bash

在容器内执行 HTTP 请求:

curl http://typecho

若返回 302 Redirect 或 HTML 网页源码,说明 nginx-proxy-manager 通过 proxy 网络访问 typecho 容器通信正常[cite: 1]。


十、NPM 配置博客域名与 SSL[cite: 1]

登录 NPM 后台,点击 Proxy HostsAdd Proxy Host,按如下参数配置[cite: 1]:

Details 选项卡[cite: 1]

  • Domain Names: blog.example.com[cite: 1]
  • Scheme: http[cite: 1]
  • Forward Hostname / IP: typecho[cite: 1]
  • Forward Port: 80[cite: 1]

SSL 选项卡[cite: 1]

  • 勾选 Block Common Exploits
  • SSL Certificate: 选择 Request a new SSL Certificate(申请免费证书)[cite: 1]
  • 勾选 Force SSL[cite: 1]
  • 勾选 HTTP/2 Support[cite: 1]

保存后,在浏览器访问 https://blog.example.com 进入 Typecho 安装界面[cite: 1]。

安装页面数据库填写项[cite: 1]

  • 数据库地址mariadb[cite: 1]
  • 数据库名typecho[cite: 1]
  • 用户名typecho[cite: 1]
  • 密码:设置的 MYSQL_PASSWORD[cite: 1]

十一、最终端口与架构总结[cite: 1]

端口开放规划[cite: 1]

端口号服务说明开放状态
22222SSH 远程登录开放(公网)[cite: 1]
80HTTP 流量入站开放(公网)[cite: 1]
443HTTPS 安全流量入站开放(公网)[cite: 1]
81NPM 后台管理关闭(仅允许 127.0.0.1 / SSH 隧道)[cite: 1]
3306MariaDB 数据库关闭(仅限内部网络)[cite: 1]
8080Typecho 容器端口关闭(仅限内部网络)[cite: 1]

架构总览图[cite: 1]

Docker 宿主机环境
│
├── nginx-proxy-manager
│       ├── 公网端口: 80, 443
│       └── 本地监听: 127.0.0.1:81
│
├── typecho
│       └── 内部运行: Apache + PHP
│
└── typecho-db
        └── 内部运行: MariaDB

架构优势[cite: 1]

  • 服务高度隔离:容器职责单一,互不干扰[cite: 1]。
  • 数据持久化:关键数据挂载至宿主机目录,易于备份[cite: 1]。
  • HTTPS 自动化:自动化证书申请与强制跳转[cite: 1]。
  • 高安全性:核心应用及数据库不直接暴露于公网[cite: 1]。
  • 极佳扩展性:未来新增服务只需加入对应网络即可[cite: 1]。

未来扩展蓝图[cite: 1]

proxy 网络:
├── Typecho
├── MinIO (图床)
├── Uptime Kuma (状态监控)
└── 其他 Web 应用

database 网络:
├── MariaDB
├── Redis
└── PostgreSQL

这套 Docker 架构可以作为个人服务器长期运行的稳定基础环境[cite: 1]。