国庆节10月1日
--


介绍Waline如何从 Vercel 迁移到腾讯云服务器。

本教程记录了将 Waline 评论系统从 Vercel 迁移到腾讯云服务器的完整过程,使用宝塔面板 + Docker 部署,基于 SQLite 数据库。
适用场景:Vercel 数据库额度用完、想自建服务、需要更灵活的配置。
| 项目 | 最低要求 |
|---|---|
| CPU | 1 核 |
| 内存 | 1 GB |
| 带宽 | 1 Mbps(评论系统数据量小,够用) |
| 系统 | Ubuntu 22.04 / CentOS 7+ / OpenCloudOS |
在腾讯云控制台 → 防火墙 / 安全组,放行以下端口:
| 端口 | 用途 |
|---|---|
| 22 | SSH 远程连接 |
| 80 | HTTP |
| 443 | HTTPS |
| 8888 | 宝塔面板 |
⚠️ Waline 服务端口 8360 不需要对外开放,通过 Nginx 反向代理即可。
将你的域名(如 waline.tsh520.cn)A 记录指向服务器公网 IP。
SSH 连接服务器后执行:
1# Ubuntu / Debian2wget -O install.sh https://download.bt.cn/install/install-ubuntu_6.0.sh && sudo bash install.sh3
4# CentOS5yum install -y wget && wget -O install.sh https://download.bt.cn/install/install_6.0.sh && sh install.sh6
7# OpenCloudOS(与 CentOS 兼容)8yum install -y wget && wget -O install.sh https://download.bt.cn/install/install_6.0.sh && sh install.sh安装完成后会显示:
http://你的公网IP:8888/安全入口⚠️ 务必保存好用户名和密码!
首次登录面板后,会提示安装 LNMP 环境套件,点击「跳过」——Waline 是 Node.js 项目,不需要 PHP。
宝塔面板 → 软件商店 → 搜索 Docker管理器 → 安装
1# Ubuntu / Debian2curl -fsSL https://get.docker.com | sh3systemctl start docker4systemctl enable docker5
6# CentOS / OpenCloudOS7yum install -y docker8systemctl start docker9systemctl enable docker验证安装:
1docker --version1mkdir -p /opt/waline/data1cat > /opt/waline/docker-compose.yml << 'EOF'2version: '3'3
4services:5 waline:6 container_name: waline7 image: lizheming/waline:latest8 restart: always9 ports:10 - "127.0.0.1:8360:8360"11 volumes:12 - ./data:/app/data13 environment:14 TZ: 'Asia/Shanghai'15 SQLITE_PATH: '/app/data'16 JWT_TOKEN: '替换为你的密钥'17 SITE_NAME: '你的网站名称'18 SITE_URL: 'https://你的域名'19 SECURE_DOMAINS: '你的域名'20 AUTHOR_EMAIL: '你的邮箱'21EOF⚠️ 请将以上
JWT_TOKEN、SITE_NAME、SITE_URL、SECURE_DOMAINS、AUTHOR_EMAIL替换为你自己的值。
配置说明:
| 变量 | 说明 | 示例 |
|---|---|---|
JWT_TOKEN | JWT 密钥,用于加密 token,建议用复杂字符串 | mySecretKey123!@# |
SITE_NAME | 网站名称 | 团子和蛋糕 |
SITE_URL | 网站地址(带 https) | https://waline.tsh520.cn |
SECURE_DOMAINS | 允许的域名(防止跨站请求) | waline.tsh520.cn |
| AUTHOR_EMAIL | 博主邮箱(用于接收评论通知) | your@email.com |
| SQLITE_PATH | SQLite 数据库存储路径 | /app/data |
1cd /opt/waline && docker compose up -d1# 查看容器状态2docker ps3
4# 测试服务是否响应5curl http://127.0.0.1:8360正常情况下应返回 HTML 页面内容。
Waline 使用 SQLite 数据库时,表可能不会自动创建,需要手动建表。
1docker exec -it waline sh容器基于 Debian 系统,使用 apt 安装:
1apt-get update && apt-get install -y sqlite31sqlite3 /app/data/waline.sqlite "2CREATE TABLE IF NOT EXISTS wl_comment (3 id INTEGER PRIMARY KEY AUTOINCREMENT,4 user_id INTEGER DEFAULT NULL,5 comment TEXT,6 insertedAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,7 ip TEXT DEFAULT '',8 link TEXT DEFAULT NULL,9 mail TEXT DEFAULT NULL,10 nick TEXT DEFAULT NULL,11 pid INTEGER DEFAULT NULL,12 rid INTEGER DEFAULT NULL,13 sticky INTEGER DEFAULT NULL,14 status TEXT NOT NULL DEFAULT '',15 \"like\" INTEGER DEFAULT NULL,16 ua TEXT,17 url TEXT DEFAULT NULL,18 createdAt DATETIME DEFAULT CURRENT_TIMESTAMP,19 updatedAt DATETIME DEFAULT CURRENT_TIMESTAMP20);21
22CREATE TABLE IF NOT EXISTS wl_counter (23 id INTEGER PRIMARY KEY AUTOINCREMENT,24 time INTEGER DEFAULT NULL,25 reaction0 INTEGER DEFAULT NULL,26 reaction1 INTEGER DEFAULT NULL,27 reaction2 INTEGER DEFAULT NULL,28 reaction3 INTEGER DEFAULT NULL,29 reaction4 INTEGER DEFAULT NULL,30 reaction5 INTEGER DEFAULT NULL,31 reaction6 INTEGER DEFAULT NULL,32 reaction7 INTEGER DEFAULT NULL,33 reaction8 INTEGER DEFAULT NULL,34 url TEXT NOT NULL DEFAULT '',35 createdAt DATETIME DEFAULT CURRENT_TIMESTAMP,36 updatedAt DATETIME DEFAULT CURRENT_TIMESTAMP37);38
39CREATE TABLE IF NOT EXISTS wl_users (40 id INTEGER PRIMARY KEY AUTOINCREMENT,41 display_name TEXT NOT NULL DEFAULT '',42 email TEXT NOT NULL DEFAULT '',43 password TEXT NOT NULL DEFAULT '',44 type TEXT NOT NULL DEFAULT '',45 label TEXT DEFAULT NULL,46 url TEXT DEFAULT NULL,47 avatar TEXT DEFAULT NULL,48 github TEXT DEFAULT NULL,49 twitter TEXT DEFAULT NULL,50 facebook TEXT DEFAULT NULL,51 google TEXT DEFAULT NULL,52 weibo TEXT DEFAULT NULL,53 qq TEXT DEFAULT NULL,54 oidc TEXT DEFAULT NULL,55 huawei TEXT DEFAULT NULL,56 \"2fa\" TEXT DEFAULT NULL,57 createdAt DATETIME DEFAULT CURRENT_TIMESTAMP,58 updatedAt DATETIME DEFAULT CURRENT_TIMESTAMP59);60"1exit2docker restart waline关于这三张表:
wl_comment:存储评论数据wl_counter:存储文章访问计数wl_users:存储用户信息(管理员、评论者)表名必须是小写:
wl_comment、wl_counter、wl_users,不能写成wl_Comment或wl_User。
宝塔面板 → 软件商店 → 搜索 Nginx → 安装
宝塔面板 → 网站 → 添加站点
waline.tsh520.cn点击站点 → 设置 → 反向代理 → 添加反向代理
| 配置项 | 值 |
|---|---|
| 代理名称 | waline |
| 目标URL | http://127.0.0.1:8360 |
| 发送域名 | $host |
点击反向代理的 编辑 按钮,将配置替换为以下内容:
1#PROXY-START/2
3location ^~ /4{5 # CORS 预检请求处理6 if ($request_method = 'OPTIONS') {7 add_header 'Access-Control-Allow-Origin' '$http_origin' always;8 add_header 'Access-Control-Allow-Methods' 'GET,POST,PUT,DELETE,OPTIONS' always;9 add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type' always;10 add_header 'Access-Control-Max-Age' 1728000 always;11 add_header 'Content-Length' 0;12 return 204;13 }14
15 proxy_pass http://127.0.0.1:8360;16 proxy_set_header Host $host;17 proxy_set_header X-Real-IP $remote_addr;18 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;19 proxy_set_header X-Forwarded-Proto $scheme;20 proxy_set_header REMOTE-HOST $remote_addr;21 proxy_set_header Upgrade $http_upgrade;22 proxy_set_header Connection $connection_upgrade;23 proxy_http_version 1.1;24
25 add_header X-Cache $upstream_cache_status;26 add_header 'Access-Control-Allow-Origin' '$http_origin' always;27 add_header 'Access-Control-Allow-Methods' 'GET,POST,PUT,DELETE,OPTIONS' always;28 add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type' always;29
30 set $static_filew6OwwKmG 0;31 if ( $uri ~* "\.(gif|png|jpg|css|js|woff|woff2)$" )32 {33 set $static_filew6OwwKmG 1;34 expires 1m;35 }36 if ( $static_filew6OwwKmG = 0 )37 {38 add_header Cache-Control no-cache;39 }40}41
42#PROXY-END/为什么要加 CORS 配置?
Waline 管理后台(
/ui/register、/ui/login)会通过 JavaScript 发送 POST 请求到 API 接口。浏览器会先发送OPTIONS预检请求,如果 Nginx 没有正确处理 CORS,浏览器会拦截请求,导致注册/登录时提示 “NetworkError when attempting to fetch resource” 或 “Failed to fetch”。
保存后在服务器上重载 Nginx:
1nginx -t && nginx -s reload站点设置 → SSL → Let’s Encrypt
申请成功后,勾选 强制 HTTPS。
访问 https://你的域名/ui/register,填写邮箱和密码注册。
第一个注册的用户自动成为 管理员。
1curl -X POST https://你的域名/api/user \2 -H "Content-Type: application/json" \3 -H "Referer: https://你的域名/ui/register" \4 -H "Origin: https://你的域名" \5 -d '{"email":"你的邮箱","password":"你的密码","display_name":"你的昵称"}'返回 {"errno":0,"errmsg":"","data":""} 表示注册成功。
访问 https://你的域名/ui/login,用刚才注册的邮箱和密码登录。
配置邮件服务后可以实现:
第一步:获取 QQ 邮箱授权码
⚠️ 授权码不是 QQ 密码!务必保存好。
第二步:修改 docker-compose.yml
编辑 /opt/waline/docker-compose.yml,在 environment 中添加:
1 # 邮件配置2 SMTP_SERVICE: 'QQ'3 SMTP_USER: '你的QQ邮箱'4 SMTP_PASS: '你的16位授权码'5 SENDER_EMAIL: '你的QQ邮箱'6 SENDER_NAME: '你的网站名称'第三步:重启容器
1cd /opt/waline && docker compose up -d| 服务商 | SMTP_SERVICE | SMTP_HOST | SMTP_PORT |
|---|---|---|---|
| QQ 邮箱 | QQ | smtp.qq.com | 465 |
| 163 邮箱 | 163 | smtp.163.com | 465 |
| Gmail | Gmail | smtp.gmail.com | 465 |
| Outlook | Outlook | smtp.office365.com | 587 |
如果服务商不在预设列表中,使用 SMTP_HOST + SMTP_PORT + SMTP_SECURE 代替 SMTP_SERVICE:
1 SMTP_HOST: 'smtp.example.com'2 SMTP_PORT: '465'3 SMTP_SECURE: 'true'4 SMTP_USER: 'your@email.com'5 SMTP_PASS: 'your-password'| 变量 | 说明 | 必填 |
|---|---|---|
JWT_TOKEN | JWT 加密密钥 | ✅ |
SITE_NAME | 网站名称 | ✅ |
SITE_URL | 网站地址 | ✅ |
SECURE_DOMAINS | 允许的域名 | ❌ |
AUTHOR_EMAIL | 博主邮箱 | ❌ |
SQLITE_PATH | SQLite 存储路径 | ✅(SQLite 模式) |
Waline 支持多种数据库,按优先级(环境变量存在即启用):
| 数据库 | 环境变量 |
|---|---|
| LeanCloud | LEAN_KEY |
| MongoDB | MONGO_DB / MONGO_HOST |
| PostgreSQL | PG_DB / PG_HOST |
| SQLite | SQLITE_PATH |
| MySQL | MYSQL_DB / MYSQL_HOST |
| TiDB | TIDB_DB / TIDB_HOST |
| GitHub | GITHUB_TOKEN |
| 腾讯云 CloudBase | TCB_ENV |
| 变量 | 说明 |
|---|---|
SMTP_SERVICE | 邮箱服务商(自动配置 host/port) |
SMTP_HOST | SMTP 服务器地址 |
SMTP_PORT | SMTP 端口 |
SMTP_SECURE | 是否 SSL(true/false) |
SMTP_USER | 登录用户名 |
SMTP_PASS | 密码或授权码 |
SENDER_EMAIL | 发件人地址 |
SENDER_NAME | 发件人名称 |
| 变量 | 说明 |
|---|---|
SC_KEY | Server酱(微信通知) |
TG_BOT_TOKEN | Telegram Bot Token |
TG_CHAT_ID | Telegram Chat ID |
QYWX_AM | 企业微信应用 |
PUSH_PLUS_KEY | PushPlus(微信通知) |
DISCORD_WEBHOOK | Discord Webhook |
LARK_WEBHOOK | 飞书 Webhook |
LARK_SECRET | 飞书签名密钥 |
QMSG_KEY | QQ 消息推送 |
| 变量 | 说明 |
|---|---|
RECAPTCHA_V3_SECRET | Google reCAPTCHA V3 |
TURNSTILE_SECRET | Cloudflare Turnstile |
| 变量 | 说明 |
|---|---|
DISABLE_AUTHOR_NOTIFY | 禁用博主通知 |
AVATAR_PROXY | 头像代理地址 |
1# 查看容器状态2docker ps3
4# 查看日志5docker logs waline6docker logs waline --tail 100 # 最近 100 行7
8# 重启容器9docker restart waline10
11# 停止容器12docker stop waline13
14# 启动容器15docker start waline1cd /opt/waline2docker compose pull # 拉取最新镜像3docker compose up -d # 重建容器1# 备份 SQLite 数据库2cp /opt/waline/data/waline.sqlite /opt/waline/backup/waline-$(date +%Y%m%d).sqlite3
4# 创建自动备份脚本5cat > /opt/waline/backup.sh << 'EOF'6#!/bin/bash7BACKUP_DIR="/opt/waline/backup"8mkdir -p $BACKUP_DIR9cp /opt/waline/data/waline.sqlite $BACKUP_DIR/waline-$(date +%Y%m%d_%H%M%S).sqlite10# 保留最近 30 天的备份11find $BACKUP_DIR -name "*.sqlite" -mtime +30 -delete12EOF13
14chmod +x /opt/waline/backup.sh15
16# 添加定时任务(每天凌晨 3 点备份)17echo "0 3 * * * /opt/waline/backup.sh" | crontab -1# 测试配置2nginx -t3
4# 重载配置5nginx -s reload6
7# 查看错误日志8tail -f /www/wwwlogs/waline.tsh520.cn.error.log1# 1. 编辑配置文件2vi /opt/waline/docker-compose.yml3
4# 2. 在 environment 下添加新变量5# 格式:变量名: '值'6
7# 3. 重启容器8cd /opt/waline && docker compose up -d9
10# 4. 验证变量是否生效11docker exec waline env | grep 变量名原因:数据库表未创建或表名大小写不对。
解决:按本文第五节手动创建数据库表。注意表名必须是小写:wl_comment、wl_users、wl_counter。
原因:Nginx 反向代理没有正确处理 CORS(跨域请求)。
解决:按本文第六节编辑反向代理配置,添加 CORS 处理。
{"errno":403,"errmsg":"Forbidden"}#原因:请求缺少 Referer 或 Origin 头,Waline 的安全检查拒绝了请求。
解决:
1-H "Referer: https://你的域名/ui/register"2-H "Origin: https://你的域名"原因:未配置邮件服务。
解决:按本文第九节配置 SMTP 环境变量。
1# 查看详细错误2docker logs waline3
4# 检查端口是否被占用5netstat -tlnp | grep 8360修改 docker-compose.yml,去掉 SQLITE_PATH,添加数据库连接信息:
MySQL 示例:
1 MYSQL_HOST: '你的数据库地址'2 MYSQL_PORT: '3306'3 MYSQL_DB: 'waline'4 MYSQL_USER: '用户名'5 MYSQL_PASSWORD: '密码'PostgreSQL 示例:
1 PG_HOST: '你的数据库地址'2 PG_PORT: '5432'3 PG_DB: 'waline'4 PG_USER: '用户名'5 PG_PASSWORD: '密码'⚠️ 切换数据库后,评论数据不会自动迁移。需要手动导出再导入。
1version: '3'2
3services:4 waline:5 container_name: waline6 image: lizheming/waline:latest7 restart: always8 ports:9 - "127.0.0.1:8360:8360"10 volumes:11 - ./data:/app/data12 environment:13 TZ: 'Asia/Shanghai'14 SQLITE_PATH: '/app/data'15 JWT_TOKEN: '你的JWT密钥'16 SITE_NAME: '你的网站名称'17 SITE_URL: 'https://你的域名'18 SECURE_DOMAINS: '你的域名'19 AUTHOR_EMAIL: '你的邮箱'20 # 邮件通知(可选)21 SMTP_SERVICE: 'QQ'22 SMTP_USER: '你的QQ邮箱'23 SMTP_PASS: '你的16位授权码'24 SENDER_EMAIL: '你的QQ邮箱'25 SENDER_NAME: '你的网站名称'26 # 微信通知(可选,二选一)27 # SC_KEY: '你的Server酱Key'28 # PUSH_PLUS_KEY: '你的PushPlus Key'29 # Telegram 通知(可选)30 # TG_BOT_TOKEN: '你的Bot Token'31 # TG_CHAT_ID: '你的Chat ID'如果你喜欢,那么欢迎来到我的世界!
了解更多暂未播放



"所有的相遇都是久别重逢。"—— 未知


