py2htmlblog 发布与部署指南

从构建到上线:三种发布方式的详细配置与最佳实践。

概述

py2htmlblog 执行 python main.py build 后,静态站点生成在 wwwroot/ 目录中。将 wwwroot/ 部署到线上有三种内置方式:

方式 适用场景 传输协议 需要安装
FTP 虚拟主机、cPanel 空间 FTP 无(Python 内置)
SFTP VPS、云服务器 SSH File Transfer pip install paramiko
Git GitHub Pages、Gitee Pages Git 无(需安装 Git)

配置写在 data/info.json 的 deploy 字段中,一次配置,一键部署。


FTP 发布

适用场景

  • 传统的 PHP 虚拟主机(Bluehost、HostGator、阿里云虚拟主机等)
  • 通过 cPanel / DirectAdmin 管理的空间
  • 任何支持 FTP 上传的托管服务

配置

在 data/info.json 中添加:

{
  "deploy": {
    "method": "ftp",
    "ftp": {
      "host": "ftp.yourdomain.com",
      "port": 21,
      "user": "ftp_username",
      "password": "your-ftp-password",
      "remote_dir": "/public_html/"
    }
  }
}
参数 说明
host FTP 服务器地址
port FTP 端口,默认 21
user FTP 用户名
password FTP 密码
remote_dir 远程上传目录。虚拟主机一般是 /public_html/ 或 /htdocs/

发布

# 先构建
python main.py build

# 发布到 FTP
python main.py deploy

工作流程

  1. 连接 FTP 服务器
  2. 自动创建远程目录结构
  3. 逐个上传 wwwroot 下所有文件
  4. 显示上传进度和结果

注意事项

  • FTP 密码明文存储在 info.json 中,建议将此文件加入 .gitignore
  • 如果虚拟主机支持 SFTP,优先使用 SFTP(加密传输)
  • 某些虚拟主机的 remote_dir 可能是 / 或 ./,按需调整

SFTP 发布

适用场景

  • VPS(阿里云 ECS、腾讯云 CVM、AWS EC2 等)
  • 云服务器(DigitalOcean、Linode、Vultr 等)
  • 任何支持 SSH 登录的 Linux 服务器

安装依赖

pip install paramiko

配置

密码认证

{
  "deploy": {
    "method": "sftp",
    "sftp": {
      "host": "123.45.67.89",
      "port": 22,
      "user": "root",
      "password": "your-password",
      "remote_dir": "/var/www/html/"
    }
  }
}

SSH 密钥认证(推荐)

{
  "deploy": {
    "method": "sftp",
    "sftp": {
      "host": "123.45.67.89",
      "port": 22,
      "user": "root",
      "key_file": "~/.ssh/id_rsa",
      "remote_dir": "/var/www/html/"
    }
  }
}
参数 说明
host 服务器 IP 或域名
port SSH 端口,默认 22
user SSH 用户名
password 密码(与 key_file 二选一)
key_file SSH 私钥路径(支持 ~ 展开)
remote_dir 远程 Web 目录。常见路径:/var/www/html/、/usr/share/nginx/html/

发布

# 构建 + 发布
python main.py build
python main.py deploy

智能增量上传

SFTP 发布会自动比较文件修改时间,只上传有变化的文件,跳过未修改的文件,大幅提升多次发布的速度。

# 第一次发布:全部上传
[1/50] ✓ index.html
[2/50] ✓ archives.html
...

# 第二次发布:只上传变更
[1/50] - index.html (未变化,跳过)
[2/50] ✓ archives.html  ← 这里改了
[3/50] - rss.xml (未变化,跳过)
...

安全建议

  • 优先使用密钥:password 留空,只用 key_file
  • 限制 SSH 用户权限:不要用 root,创建一个只对 Web 目录有写权限的专用用户
  • 文件权限:确保远程目录的所有者与 SSH 用户一致
  # 在服务器上
  sudo chown -R deploy:deploy /var/www/html/

Git 发布

适用场景

  • GitHub Pages — username.github.io 仓库
  • Gitee Pages — Gitee 提供的静态页面服务
  • Coding Pages — 腾讯云开发者平台的静态托管
  • 自建 Git 服务器 — 通过 Git Hooks 自动部署

配置

{
  "deploy": {
    "method": "git",
    "git": {
      "remote": "origin",
      "branch": "main",
      "repo_dir": "D:/projects/my-blog",
      "commit_message": "Site update: {{date}}",
      "sub_dir": ""
    }
  }
}
参数 说明
remote 远程仓库名,默认 origin
branch 推送分支,GitHub Pages 通常为 main 或 gh-pages
repo_dir 本地 Git 仓库的绝对路径
commit_message 提交信息(支持 {{date}} 自动替换为当前日期)
sub_dir 子目录(如有需要在仓库子目录中部署)

GitHub Pages 典型设置

假设你的 GitHub Pages 仓库是 https://github.com/username/username.github.io,已 clone 到本地 D:/projects/username.github.io/:

{
  "deploy": {
    "method": "git",
    "git": {
      "remote": "origin",
      "branch": "main",
      "repo_dir": "D:/projects/username.github.io",
      "commit_message": "Blog update {{date}}"
    }
  }
}

发布流程:

  1. 清空 D:/projects/username.github.io/ 下的旧文件(保留 .git)
  2. 将 wwwroot/ 所有文件复制进去
  3. 执行 git add -A && git commit -m "Blog update 2026-07-22"
  4. 执行 git push origin main
  5. GitHub Actions 自动部署(或直接生效,取决于配置)

Gitee Pages 设置

Gitee Pages 需要手动点击"更新"按钮。推送后记得去 Gitee Pages 设置页触发重新部署。

{
  "deploy": {
    "method": "git",
    "git": {
      "remote": "origin",
      "branch": "master",
      "repo_dir": "D:/projects/gitee-blog",
      "commit_message": "Site update"
    }
  }
}

注意事项

  • repo_dir 必须是已经 clone 好的 Git 仓库
  • 确保本地仓库已正确设置 remote:git remote -v
  • 如果使用 HTTPS 认证,确保已配置 Git 凭据管理器(git config credential.helper)
  • 如果使用 SSH 认证,确保 SSH key 已添加到 GitHub/Gitee

模拟运行

不确定配置是否正确?使用 --dry-run 参数预览:

python main.py deploy --dry-run

输出示例:

FTP → ftp_user@ftp.example.com:21
远程目录: /public_html/
文件数: 25
[模拟运行] 不会实际上传

  [DRY-RUN] index.html
  [DRY-RUN] archives.html
  [DRY-RUN] rss.xml
  [DRY-RUN] sitemap.xml
  [DRY-RUN] css/style.css
  [DRY-RUN] archives/cat_log.html
  ...

一键构建 + 发布

构建和发布是两个步骤,但可以合并为一条命令:

python main.py build && python main.py deploy

或通过 publish 命令(它会先处理 mdblog 再构建,但不包含 deploy):

python main.py publish && python main.py deploy

如果需要更自动化的流程,可以写一个简单的脚本:

Windows (build-and-deploy.bat):

@echo off
python main.py build
if %errorlevel% equ 0 (
    python main.py deploy
) else (
    echo 构建失败,取消发布
)

Linux/Mac (build-and-deploy.sh):

#!/bin/bash
python main.py build && python main.py deploy

常见问题

Q: FTP 上传失败:"550 Permission denied"

A: 检查 remotedir 路径是否正确。虚拟主机通常不允许写入根目录,确保路径指向 publichtml 或 htdocs。

Q: SFTP 连接超时

A: 检查服务器防火墙是否开放了 SSH 端口(默认 22)。如果服务器换了 SSH 端口,修改 port 参数。

Q: Git push 失败:"Permission denied (publickey)"

A: SSH 密钥未配置或未添加到 GitHub/Gitee。检查:

ssh -T git@github.com   # 测试 GitHub 连接

如果失败,重新生成并添加 SSH 密钥。

Q: 为什么 Git 发布要清空仓库?

A: 确保仓库中的文件与 wwwroot 完全同步,避免残留删除的文章页面。如果你有需要在仓库中保留的文件,可以使用 sub_dir 参数将博客部署到子目录。

Q: 可以同时配置多个发布方式吗?

A: 每次只能使用一种。如果需要切换,修改 deploy.method 的值即可。所有子配置(ftp/sftp/git)可以同时填写,系统只读取当前 method 对应的配置。

Q: 上传时会覆盖远程已有文件吗?

A: 会。FTP 和 Git 是全量同步。SFTP 会对比修改时间,只上传变更的文件。