项目初衷与定位

为个人开发者与小团队打造的开箱即用数字商品发卡平台。

Asolica 源于对"轻量化自托管"的追求。我们摒弃臃肿架构,用 Vue 3 + Express + SQLite 极简技术栈,实现5分钟部署、1核1G稳定运行、数据完全自主可控。

核心特性:AES-GCM-256字段级加密、异步邮件队列、多支付网关适配、Telegram/Bark实时推送,为每一位开发者提供安心稳定的发卡体验。

PM2 升级(保留数据)

升级新版并保留订单、卡密、商品和配置,全程自动迁移表结构。

升级步骤
  1. 停止服务pm2 stop asolica-server
  2. 备份数据(务必执行):
    $ cp -r server/data /backup/asolica_data_$(date +%Y%m%d)
    $ cp -r server/uploads /backup/asolica_uploads_$(date +%Y%m%d) 2>/dev/null || true
  3. 替换源码:保留 server/dataserver/uploads,删除其他旧文件,上传新版源码
  4. 安装依赖并重启
    $ bash install.sh
    $ pm2 restart asolica-server

启动时系统会自动执行数据库迁移,无需手动操作。跨大版本升级建议先在测试环境验证。

Docker 升级(保留数据)

Docker Compose 模式下安全升级,数据通过卷挂载持久化,重建容器不会丢失。

升级命令
$ cd /path/to/asolica
$ docker compose down
$ cp -r server/data server/data_backup_$(date +%Y%m%d)
$ docker compose up -d --build
$ docker compose logs -f app
⚠️ 严禁执行 docker compose down -v

-v 参数会删除数据卷,导致数据永久丢失!不要手动删除宿主机 server/data 目录。

Docker 全新部署

彻底清除旧数据,从零开始安装。此操作不可逆,数据将永久删除。

⚠️ 数据清除警告 以下操作将删除所有商品、订单、卡密、配置数据,执行前请确认已备份!
清除步骤
$ docker compose down -v
$ rm -rf server/data server/uploads .env
$ docker volume prune -f

重新初始化

  1. cp .env.example .env,编辑配置JWT_SECRET等参数
  2. docker compose up -d --build
  3. 查看初始密码:cat server/data/admin_password.txt

PM2 全新部署

彻底清除旧数据,从零开始PM2部署。

清除重装步骤
  1. 停止并删除PM2进程
    $ pm2 stop asolica-server
    $ pm2 delete asolica-server
    $ pm2 save
    $ pkill -f "node.*app.js" || true
  2. 删除旧项目目录rm -rf /www/wwwroot/asolica
  3. 确认端口释放ss -tlnp | grep 3200(应无输出)
  4. 解压新版并安装:解压到原目录后执行 bash install.sh,系统会自动生成新数据库和初始密码

PM2 缓存问题

解决升级后仍显示旧版本/旧数据的PM2缓存问题。

现象:替换源码并重启PM2后,页面仍显示旧版本。

原因:Node.js常驻内存,PM2 restart未彻底释放旧进程内存和文件句柄。

正确解决方案

使用 delete + 重新启动替代 restart:

$ pm2 delete asolica-server
$ pkill -f "node.*app.js" || true
$ cd /www/wwwroot/asolica
$ pm2 start ecosystem.config.cjs --env production
$ pm2 save

项目架构与技术栈

前后端分离架构,极简技术选型。

层级技术说明
前端Vue 3 + ViteComposition API,Pinia状态管理,Vue Router
后端Express.jsNode.js RESTful API,JWT鉴权
数据库SQLite (better-sqlite3)WAL模式,单文件零配置
安全AES-GCM-256 + bcrypt字段级加密,密码强散列
校验Zod前后端统一Schema验证

架构分层:前端静态资源由Nginx托管,API请求反向代理到Express后端,SQLite本地文件存储,所有敏感数据AES加密后落库。

SQLite 与性能选型

为什么选择SQLite而非MySQL?

Q: SQLite能支撑多少并发?
A: WAL模式下读写不互斥,单次查询<2ms,1核1G可支撑日均数千订单、600+TPS,完全满足中小规模发卡场景。

Q: 相比MySQL有什么优势?
A: 零配置、免运维、单文件备份迁移简单、无网络连接开销、内存占用极低(空载~28MB)。

Q: 什么时候需要换MySQL?
A: 日订单过万、多机分布式部署时再考虑迁移,Asolica当前版本专注SQLite极致优化。

数据备份与恢复

核心数据备份方案与灾难恢复。

方法1:物理拷贝(停机备份,最安全)
$ pm2 stop asolica-server
$ cp -a server/data /backup/
$ cp -a server/uploads /backup/ 2>/dev/null || true
$ cp .env /backup/
$ pm2 restart asolica-server
方法2:内置备份脚本
$ node server/scripts/backup.js
方法3:SQLite在线热备份(不停机)
$ sqlite3 server/data/asolica.db ".backup '/backup/asolica_$(date +%Y%m%d).db'"
恢复步骤

停止服务 → 用备份覆盖 server/dataserver/uploads.env → 检查权限 chown -R www:www server/data → 重启服务验证。

定时自动备份

配置Cron实现每日自动备份,保留7天。

备份脚本 /root/backup-asolica.sh
#!/bin/bash
set -e
PROJECT_DIR="/www/wwwroot/asolica"
BACKUP_ROOT="/backup/asolica"
RETENTION_DAYS=7
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_ROOT
cd $PROJECT_DIR

sqlite3 server/data/asolica.db ".backup '$BACKUP_ROOT/asolica_$DATE.db'"
cp server/data/admin_password.txt $BACKUP_ROOT/ 2>/dev/null || true
cp -a server/uploads $BACKUP_ROOT/uploads_$DATE 2>/dev/null || true
cp .env $BACKUP_ROOT/env_$DATE

cd $BACKUP_ROOT
tar -czf "${DATE}.tar.gz" asolica_$DATE.db admin_password.txt env_$DATE uploads_$DATE 2>/dev/null
rm -rf asolica_$DATE.db admin_password.txt env_$DATE uploads_$DATE
find $BACKUP_ROOT -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete
echo "Backup completed: ${DATE}.tar.gz"
配置Cron
$ chmod +x /root/backup-asolica.sh
$ mkdir -p /backup/asolica
$ crontab -e
# 添加:每天凌晨3点执行
0 3 * * * /root/backup-asolica.sh >> /var/log/asolica-backup.log 2>&1

日志查看与排查

Docker、PM2、Nginx日志查看命令。

Docker日志
$ docker compose logs -f app
$ docker compose logs --tail=100 app
$ docker compose logs --since=1h app
PM2日志
$ pm2 logs asolica-server
$ tail -f ~/.pm2/logs/asolica-server-error.log
$ pm2 flush  # 清空日志
Nginx日志(宝塔)
$ tail -f /www/wwwlogs/your-domain.log
$ tail -f /www/wwwlogs/your-domain.error.log

健康检查与监控

内置健康检查端点,支持Docker healthcheck。

健康检查接口
$ curl https://your-domain.com/api/health
# 正常响应: {"status":"ok","db":"connected","uptime":3600}
Docker healthcheck配置

在docker-compose.yml中添加:

    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3200/api/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 20s

推荐使用Uptime Kuma等开源监控工具监控 /api/health 端点,异常时邮件/Telegram告警。关键指标:内存(空载~28MB)、磁盘空间、系统负载。

性能调优

高并发场景优化配置。

SQLite WAL模式优化(已默认配置)
PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;
PRAGMA cache_size = -20000;  # 20MB缓存
PRAGMA busy_timeout = 5000;
PRAGMA temp_store = MEMORY;
Node.js内存限制

编辑 ecosystem.config.cjs

    node_args: '--max-old-space-size=256',
Nginx Gzip压缩
gzip on;
gzip_vary on;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
gzip_min_length 1024;

邮件服务配置

支持SMTP、Resend、阿里云邮件、腾讯云邮件4种驱动,异步队列发送。

.env配置项
# 驱动: smtp / resend / aliyun / qcloud
MAIL_DRIVER=smtp
MAIL_FROM_NAME="Asolica Store"
MAIL_FROM_ADDRESS="n***@example.com"

# SMTP配置
SMTP_HOST=smtp.qq.com
SMTP_PORT=465
SMTP_SECURE=true
SMTP_USER=n***@qq.com
SMTP_PASS=your-authorization-code

# Resend
RESEND_API_KEY=re_xxx

# 阿里云/腾讯云密钥配置略
常见坑点
  • QQ/163邮箱SMTP密码是授权码,不是登录密码,需在邮箱设置中开启SMTP并生成
  • MAIL_FROM_ADDRESS必须与SMTP_USER一致
  • 25端口常被封禁,推荐用465(SSL)或587(STARTTLS)

后台"系统设置"中点击"发送测试邮件"验证,数据库 email_queue 表可查看发送状态和失败原因。

支付网关对接

支持彩虹易支付、虎皮椒,回调幂等校验防重复发卡。

彩虹易支付配置
  1. 注册易支付商户,获取商户ID和密钥
  2. 后台支付设置选择"彩虹易支付",填写网关地址、商户ID、密钥
  3. 回调URL:https://你的域名/api/v1/payment/callback/epay
  4. 易支付后台设置异步通知地址为上述URL
虎皮椒配置
  1. 注册xunhupay.com,创建应用获取APP_ID和APP_SECRET
  2. 后台填写对应参数
  3. 回调URL:https://你的域名/api/v1/payment/callback/xunhupay
重要提醒

BASE_URL必须配置为https://开头的正式域名,配置错误将导致无法接收支付回调!

测试:创建0.01元测试商品下单支付,验证是否自动发卡、订单状态更新、邮件通知正常。

Telegram/Bark推送

新订单、库存预警实时推送到手机。

Telegram Bot配置
  1. 找@BotFather发送/newbot创建Bot,获取Bot Token
  2. 给你的Bot发一条消息
  3. 访问 https://api.telegram.org/bot<TOKEN>/getUpdates 获取Chat ID
  4. 后台通知设置填入TG_BOT_TOKEN和TG_CHAT_ID,测试发送
Bark (iOS)配置
  1. App Store下载Bark,复制推送URL(https://api.day.app/xxxxx/
  2. 后台填入BARK_PUSH_URL,测试发送

触发场景:新订单支付成功、库存不足预警、系统异常告警。

优惠券系统

支持固定金额折扣和百分比折扣两种类型。

固定金额:直接减免指定金额(如满10减5);百分比折扣:按比例折扣(如8折设为0.8)。

后台营销→优惠券新建,填写优惠券码、折扣类型、有效期、适用商品、最大使用次数。买家结算页输入券码自动抵扣。

注意:单笔订单只能用一张券,过期/达次数上限自动失效。

HTTPS/SSL配置

支付网关强制要求HTTPS,两种配置方式。

方法1:宝塔一键配置(推荐)
  1. 宝塔网站设置→SSL→Let's Encrypt免费证书
  2. 勾选域名申请,成功后开启"强制HTTPS"
  3. 证书自动续期
方法2:Nginx手动配置
server {
    listen 443 ssl http2;
    server_name your-domain.com;
    ssl_certificate     /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;
}
server { listen 80; server_name your-domain.com; return 301 https://$host$request_uri; }

Nginx安全配置

隐藏版本、安全响应头、禁止敏感文件访问。

完整配置(添加到server{}块内)
server_tokens off;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

location ~* \.(db|sqlite|sqlite3|log|env|sh|bak|sql)$ { deny all; return 404; }
location ~ /\. { deny all; return 404; }
autoindex off;
client_max_body_size 10m;

验证:访问https://your-domain.com/.env应返回403/404;curl -I检查响应头包含安全字段。

密钥泄露应急

JWT_SECRET泄露后的紧急处理6步骤。

风险:攻击者可伪造管理员Token登录后台,窃取数据。
立即执行:
  1. 停止服务pm2 stop asolica-serverdocker compose down
  2. 生成新密钥替换.env中JWT_SECRET:
    $ openssl rand -hex 32
  3. 重置管理员密码node server/scripts/reset-password.js
  4. 检查数据库:查看异常订单、新增管理员、卡密是否被批量导出
  5. 重启服务
  6. 通知用户:所有旧Token失效,需重新登录

最佳实践:用openssl生成随机密钥,.env不提交Git,生产测试环境用不同密钥,定期轮换。

数据与卡密安全

多层安全防护机制。

1. AES-GCM-256字段级加密:支付密钥、SMTP密码、卡密明文落库前均加密,拖库也无法破解。

2. Zod强校验:前后端统一Schema验证,拦截SQL注入和XSS。

3. JWT + bcrypt:无状态令牌鉴权,密码bcrypt单向慢哈希,免疫彩虹表暴力破解。

支付与通知通道

可插拔多渠道架构。

支付:内置彩虹易支付、虎皮椒适配器,后台热切换,回调幂等防重发。

邮件:异步队列(SMTP/Resend/阿里云/腾讯云),失败自动重试3次,不阻塞下单流程。

推送:Telegram Bot + Bark(iOS),新订单秒级通知。

中英双语支持

完整i18n国际化适配。

支持。前端商城和管理后台均使用Vue I18n实现中英双语,支持一键切换,浏览器语言自动检测,适配跨境销售场景。

server/data/目录说明

数据目录文件用途说明。

文件说明
asolica.db主数据库:商品、订单、卡密、用户、配置等所有核心数据
asolica.db-walWAL预写日志,运行时存在,正常关闭自动合并
asolica.db-shm共享内存索引,加速WAL并发访问
admin_password.txt初始管理员密码备份文件

注意:-wal-shm是WAL模式正常文件,不要手动删除,否则可能数据损坏。

故障1:手机打开空白

移动端白屏问题。

现象:电脑端正常,手机浏览器白屏,控制台报CORS/MIME错误。

原因:Nginx配置了过严的跨源隔离头(Cross-Origin-Opener-PolicyCross-Origin-Embedder-Policy)。

解决:

宝塔网站配置文件中删除这两行响应头,重载Nginx。

故障2:忘记初始密码

找回或重置管理员密码。

现象:部署后忘记初始随机密码无法登录后台。

解决方法1:查看备份文件:

$ cat server/data/admin_password.txt

解决方法2:重置脚本:

$ node server/scripts/reset-password.js

故障3:付款成功待支付

支付成功但订单状态未更新。

现象:买家已付款,但订单仍显示"待支付",未发卡。

原因:支付平台异步回调被阻断或BASE_URL配置错误。

排查:
  1. 检查.envBASE_URLhttps://开头的正确域名
  2. 检查Cloudflare/宝塔防火墙是否拦截/api/v1/payment/callback/*的POST请求

故障4:敏感文件可下载

防止.env、数据库被直接访问下载。

隐患:Nginx未配置过滤时,访问者可直接下载数据库和配置文件。

解决:

Nginx配置中添加:

location ~* \.(db|sqlite|log|env|txt|sh)$ { deny all; }

验证:访问/.env返回403。

故障5:PM2频繁崩溃

PM2显示Errored或频繁重启。

现象pm2 start后进程Errored,日志报better-sqlite3或ESM语法错误。

原因:Node.js版本过低(需v18+),或原生模块未重新编译。

解决:
  1. 安装Node.js v22 LTS
  2. 删除server/node_modules和package-lock.json
  3. 重新执行bash install.sh

故障6:SQLite写入报错

SQLITE_CANTOPEN / Permission denied。

现象:下单/保存配置返回500,日志报无法打开数据库。

原因:曾以root启动导致数据库文件属主为root,PM2以www运行无权限。

解决:
$ chown -R www:www /www/wwwroot/asolica
$ chmod -R 755 /www/wwwroot/asolica/server/data
$ pm2 restart asolica-server

故障7:Docker启动失败

容器立即退出或反复Restarting。

诊断:先看日志docker compose logs app

常见原因:
  1. 端口占用ss -tlnp | grep 3200,停止占用进程或改端口
  2. 权限问题chmod -R 755 server/data && chown -R 1000:1000 server/data
  3. .env缺失/JWT_SECRET为空
  4. Docker版本过低:需Docker 20.10+、Compose v2+

故障8:邮件发送失败

买家收不到卡密邮件。

排查清单:
  1. MAIL_DRIVER和对应驱动参数正确
  2. SMTP密码是授权码不是登录密码
  3. 端口:465→SECURE=true,587→SECURE=false,避免用25
  4. 查看email_queue表failed记录的error_message
  5. 提醒买家检查垃圾邮件箱
  6. MAIL_FROM_ADDRESSSMTP_USER必须一致