← 返回首页

部署微信小程序后端

📝 _

# 从 0 部署微信小程序后端:Ubuntu + Node.js + MySQL + Nginx 实战

> 本文记录“顺手补”微信小程序从微信云开发迁移到自有服务器的完整过程。教程面向第一次接触服务器、数据库和反向代理的开发者,并集中整理真实部署中遇到的问题与解决方法。

## 一、最终架构

这套部署方案的请求链路如下:

```text

微信小程序

↓ HTTPS 请求

https://你的域名/shunshoubu/api/*

↓ Nginx 反向代理

127.0.0.1:3100

↓ Node.js + Express

MySQL 数据库

```

各部分职责:

- 微信小程序:页面展示、交互和 wx.login

- Nginx:处理 HTTPS、域名和请求转发。

- Node.js:处理登录、家庭、补货任务等业务逻辑。

- MySQL:保存用户、家庭、成员和补货记录。

- systemd:让 Node.js 后端开机启动、异常自动重启。

本文示例环境:

- Ubuntu Server 24.04 LTS

- 2 核 CPU、2 GB 内存

- Node.js 18 或更高版本

- MySQL 8

- Nginx

- 已备案并解析到服务器的域名

## 二、部署前准备

你需要准备:

1. 一台有公网 IPv4 的 Ubuntu 服务器。

2. 一个已经解析到服务器的域名。

3. 微信小程序 AppID 和 AppSecret。

4. 可以正常运行的小程序前端代码。

5. 后端源码和数据库初始化 SQL。

安全提醒:

- AppSecret 只能保存在服务器,绝不能写进小程序前端。

- MySQL 密码不要发送到聊天、截图或 Git 仓库。

- 数据库 3306 端口不需要向公网开放。

- Node.js 服务只监听 127.0.0.1,由 Nginx 对外提供 HTTPS。

## 三、连接服务器

在 Mac 或 Linux 终端执行:

```bash

ssh ubuntu@你的服务器IP

```

推荐使用 SSH 密钥,不建议长期使用密码登录。

### 常见错误ssh-rsa: command not found

这通常是把公钥内容直接粘贴到了服务器命令行。公钥不是命令,应该写入:

```text

~/.ssh/authorized_keys

```

可以在本机使用:

```bash

ssh-copy-id ubuntu@你的服务器IP

```

或在云服务商控制台绑定密钥后重启实例。

## 四、安装运行环境

更新软件包:

```bash

sudo apt update

sudo apt upgrade -y

```

安装基础软件:

```bash

sudo apt install -y nodejs npm mysql-server nginx unzip

```

检查版本:

```bash

node -v

npm -v

mysql --version

nginx -v

```

启动并设置开机启动:

```bash

sudo systemctl enable --now mysql

sudo systemctl enable --now nginx

```

如果使用宝塔面板安装的 Nginx 或 MySQL,不要再通过 apt 重复安装另一套。先用下面的命令确认当前运行的是哪一个实例:

```bash

sudo ss -lntp | grep -E '3306|80|443'

sudo ps -ef | grep '[m]ysqld'

```

## 五、上传后端代码

本文后端目录结构如下:

```text

server/

├── package.json

├── .env.example

├── sql/

│ └── schema.sql

└── src/

└── index.js

```

在服务器创建部署目录和专用系统用户:

```bash

sudo useradd --system --home /opt/shunshoubu --shell /usr/sbin/nologin shunshoubu

sudo mkdir -p /opt/shunshoubu

sudo chown -R shunshoubu:shunshoubu /opt/shunshoubu

```

在本机项目目录上传代码:

```bash

scp -r server/* ubuntu@你的服务器IP:/tmp/shunshoubu-server/

```

回到服务器安装代码:

```bash

sudo cp -R /tmp/shunshoubu-server/. /opt/shunshoubu/

sudo chown -R shunshoubu:shunshoubu /opt/shunshoubu

cd /opt/shunshoubu

sudo -u shunshoubu npm install --omit=dev

```

## 六、创建 MySQL 数据库

“顺手补”使用五张表:

- users:微信用户。

- families:家庭。

- family_members:家庭成员关系。

- common_items:常用补货物品。

- supply_tasks:补货任务和历史记录。

使用管理员账号导入数据库结构:

```bash

mysql -uroot -p < /opt/shunshoubu/sql/schema.sql

```

进入 MySQL 后创建独立应用账户:

```sql

CREATE USER IF NOT EXISTS 'shunshoubu'@'localhost'

IDENTIFIED BY '请替换为强密码';

GRANT ALL PRIVILEGES ON shunshoubu.*

TO 'shunshoubu'@'localhost';

FLUSH PRIVILEGES;

```

应用账户只需要访问 shunshoubu 数据库,不要直接使用 root 运行后端。

### 使用宝塔面板时

可以在“数据库”页面创建:

```text

数据库名:shunshoubu

用户名:shunshoubu

访问权限:本地服务器

密码:随机强密码

```

如果数据库已经存在,不要重复删除数据库。只需要确保用户密码、权限和后端 .env 一致。

## 七、配置后端环境变量

复制示例配置:

```bash

sudo cp /opt/shunshoubu/.env.example /opt/shunshoubu/.env

sudo chmod 600 /opt/shunshoubu/.env

sudo chown shunshoubu:shunshoubu /opt/shunshoubu/.env

sudo nano /opt/shunshoubu/.env

```

填写:

```ini

PORT=3100

HOST=127.0.0.1

MYSQL_HOST=127.0.0.1

MYSQL_PORT=3306

MYSQL_USER=shunshoubu

MYSQL_PASSWORD=你的应用数据库密码

MYSQL_DATABASE=shunshoubu

WECHAT_APP_ID=你的小程序AppID

WECHAT_APP_SECRET=你的小程序AppSecret

SERVER_SESSION_SECRET=一串足够长的随机字符

```

生成会话密钥:

```bash

openssl rand -hex 32

```

注意MYSQL_PASSWORD 必须与 MySQL 中 shunshoubu@localhost 的密码完全一致。

先单独测试数据库连接:

```bash

sudo bash -c 'set -a; source /opt/shunshoubu/.env; MYSQL_PWD="$MYSQL_PASSWORD" mysql -h127.0.0.1 -u"$MYSQL_USER" "$MYSQL_DATABASE" -e "SELECT 1;"'

```

正确输出:

```text

+---+

| 1 |

+---+

| 1 |

+---+

```

只有这个测试通过,才继续启动后端。

## 八、使用 systemd 常驻运行

创建服务文件:

```bash

sudo nano /etc/systemd/system/shunshoubu.service

```

填写:

```ini

[Unit]

Description=Shunshoubu WeChat Mini Program API

After=network.target mysql.service

[Service]

Type=simple

User=shunshoubu

Group=shunshoubu

WorkingDirectory=/opt/shunshoubu

EnvironmentFile=/opt/shunshoubu/.env

ExecStart=/usr/bin/node /opt/shunshoubu/src/index.js

Restart=always

RestartSec=3

[Install]

WantedBy=multi-user.target

```

加载并启动:

```bash

sudo systemctl daemon-reload

sudo systemctl enable --now shunshoubu

sudo systemctl status shunshoubu --no-pager

```

看到 active (running) 表示服务已启动。

检查本机健康接口:

```bash

curl -sS http://127.0.0.1:3100/health

```

正确结果:

```json

{"ok":true,"service":"shunshoubu-server"}

```

查看日志:

```bash

sudo journalctl -u shunshoubu -f

```

## 九、配置 Nginx 反向代理

后端监听 127.0.0.1:3100,Nginx 将外部路径 /shunshoubu/ 转发到它。

在域名对应的 Nginx 配置中加入:

```nginx

location /shunshoubu/ {

proxy_pass http://127.0.0.1:3100/;

proxy_http_version 1.1;

proxy_set_header Host $host;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_set_header X-Forwarded-Proto $scheme;

proxy_connect_timeout 10s;

proxy_read_timeout 30s;

proxy_send_timeout 30s;

}

```

这里最容易写错的是 proxy_pass 末尾的 /。按上面的写法:

```text

/shunshoubu/api/login

```

会被正确转发为:

```text

/api/login

```

检查并重载:

```bash

sudo nginx -t

sudo systemctl reload nginx

```

公网测试:

```bash

curl -sS https://你的域名/shunshoubu/health

```

## 十、配置 HTTPS

微信小程序正式环境必须使用可信 HTTPS。

可以使用宝塔面板申请 Let's Encrypt 证书,也可以使用 Certbot:

```bash

sudo apt install -y certbot python3-certbot-nginx

sudo certbot --nginx -d 你的域名

```

申请后再次测试:

```bash

curl -I https://你的域名/shunshoubu/health

```

不要使用自签名证书,也不要忽略证书过期问题。

## 十一、小程序端配置

前端配置文件:

```js

module.exports = {

USE_SERVER: true,

API_BASE_URL: "https://你的域名/shunshoubu",

USE_CLOUD: true

}

```

在微信公众平台进入:

```text

开发管理 → 开发设置 → 服务器域名

```

request 合法域名 中填写:

```text

https://你的域名

```

注意:这里只填域名,不能填写 /shunshoubu 路径。

正式测试时应开启合法域名校验,不要长期依赖开发者工具的“不校验合法域名”选项。

## 十二、登录流程原理

微信登录过程如下:

1. 小程序调用 wx.login() 获取临时 code

2. 小程序把 code 发送到后端 /api/login

3. 后端使用 AppID、AppSecret 和 code 请求微信 jscode2session

4. 微信返回用户的 openid

5. 后端把用户写入 MySQL,并生成 JWT 登录令牌。

6. 小程序保存令牌,后续请求通过 Authorization: Bearer ... 鉴权。

AppSecret 全程只存在服务器端。

## 十三、完整验收流程

部署完成后,不要只看健康接口。至少完成以下测试:

1. 首次打开自动登录。

2. 创建家庭并生成邀请码。

3. 退出家庭。

4. 第二个微信账号通过邀请码加入。

5. 添加补货任务。

6. 第二个账号认领任务。

7. 取消认领。

8. 再次认领并标记已买到。

9. 历史记录正常显示。

10. 完全退出小程序后重新打开,登录和家庭仍然存在。

## 十四、真实故障排查记录

### 1. 健康接口正常,但小程序一直显示“连接超时”

最初容易误判为域名、IPv6 或微信接口故障。实际应先打开微信开发者工具 Console,查看真正的 HTTP 状态和后端错误。

本次真实错误是:

```text

POST /shunshoubu/api/login 500

Access denied for user 'shunshoubu'@'localhost' (using password: YES)

```

结论:Nginx 和 Node.js 都正常,后端在访问 MySQL 时认证失败。

修复原则:

1. 确认 .env 中的 MYSQL_USER

2. 确认 MySQL 中存在相同的 user@host

3. 重新设置数据库用户密码。

4. 给该用户授权目标数据库。

5. 让 .env 密码与 MySQL 密码完全一致。

6. 先运行 SELECT 1 测试,再重启后端。

### 2. Operation ALTER USER failed for 'shunshoubu'@'localhost'

原因:要修改的账号不存在,或者存在的是另一个 Host,例如 %127.0.0.1

正确顺序:

```sql

CREATE USER IF NOT EXISTS 'shunshoubu'@'localhost'

IDENTIFIED BY '新密码';

ALTER USER 'shunshoubu'@'localhost'

IDENTIFIED BY '新密码';

GRANT ALL PRIVILEGES ON shunshoubu.*

TO 'shunshoubu'@'localhost';

FLUSH PRIVILEGES;

```

### 3. root@localhost Access denied

原因可能包括:

- 输入的是服务器密码,而不是 MySQL root 密码。

- 宝塔记录的 root 密码与实际 MySQL 不一致。

- 服务器同时安装了两套 MySQL,面板管理的不是当前 3306 实例。

- root 账号的 Host 或认证插件不同。

先确认实例:

```bash

sudo ss -lntp | grep 3306

sudo ps -ef | grep '[m]ysqld'

```

宝塔环境中可通过“数据库 → root密码”重置,再使用:

```bash

mysql -h127.0.0.1 -P3306 -uroot -p

```

### 4. phpMyAdmin 返回 #1227 CREATE USER privilege

这说明 phpMyAdmin 登录的是普通应用账户,不是 root。普通账户不能创建或删除 MySQL 用户。

解决方法:退出 phpMyAdmin,使用 MySQL root 登录后再执行用户管理 SQL;或者直接使用宝塔数据库管理页面修改应用用户密码和权限。

### 5. Nginx 日志中没有 /api/login

执行:

```bash

sudo grep '/shunshoubu/api/login' /var/log/nginx/access.log | tail

```

如果完全没有输出,说明请求根本没到 Nginx,应检查:

- 小程序 API_BASE_URL

- 微信 request 合法域名。

- 本机 DNS 和网络。

- 开发者工具代理设置。

- 是否打开了正确的项目目录和 AppID。

如果有请求记录:

- 200:后端正常。

- 400/401:参数、登录 code 或认证问题。

- 500:后端代码或数据库错误。

- 499/504:客户端取消或上游超时。

### 6. IPv4 正常,IPv6 失败

分别测试:

```bash

curl -4 -sS --max-time 10 https://你的域名/shunshoubu/health

curl -6 -sS --max-time 10 https://你的域名/shunshoubu/health

```

如果 DNS 配置了 AAAA,但 IPv6 服务没有正确监听,部分客户端可能优先走 IPv6 并超时。可以完善 IPv6 防火墙和 Nginx 配置,或在暂不使用 IPv6 时删除错误的 AAAA 记录。

### 7. systemd 显示运行,但接口仍不可用

检查最近日志:

```bash

sudo journalctl -u shunshoubu --since "10 minutes ago" --no-pager

```

检查端口:

```bash

sudo ss -lntp | grep 3100

```

检查本机接口:

```bash

curl -v http://127.0.0.1:3100/health

```

如果本机接口正常而公网失败,问题通常在 Nginx、HTTPS、安全组或域名解析。

## 十五、上线前安全检查

- .env 权限设为 600

- AppSecret 不进入 Git。

- 不向公网开放 MySQL 3306。

- Node.js 只监听 127.0.0.1

- 使用独立 MySQL 账户,不使用 root。

- JWT 密钥使用随机长字符串。

- 定期备份数据库。

- 删除生产页面中的调试按钮和内部错误详情。

- 上传小程序时排除 server/cloudfunctions/.env、SQL 和部署脚本。

- 开启 HTTPS 证书自动续期。

数据库备份示例:

```bash

mysqldump -h127.0.0.1 -ushunshoubu -p shunshoubu \

| gzip > "shunshoubu-$(date +%F).sql.gz"

```

## 十六、发布小程序

完成真机验收后:

1. 微信开发者工具点击“上传”。

2. 填写版本号,例如 1.1.0

3. 微信公众平台进入“版本管理”。

4. 先设为体验版,用两个微信账号测试。

5. 提交审核。

6. 审核通过后发布。

已经上线的旧版本不会自动使用本地新代码,必须重新上传、审核和发布。

## 总结

部署微信小程序自有后端时,最重要的不是一次写完所有配置,而是按请求链路逐层验证:

```text

MySQL SELECT 1

Node.js 127.0.0.1 健康接口

Nginx HTTPS 公网健康接口

微信 wx.login

创建家庭和业务写入

```

每一层通过后再检查下一层。这样即使页面只显示“连接超时”,也能快速定位到底是小程序、Nginx、Node.js、微信接口还是 MySQL 出了问题。

评论