关于 Asolica 发卡平台的项目设计初衷、版本升级指南、运维备份、功能配置、安全加固以及故障排除完整指南。
为个人开发者与小团队打造的开箱即用数字商品发卡平台。
Asolica 源于对"轻量化自托管"的追求。我们摒弃臃肿架构,用 Vue 3 + Express + SQLite 极简技术栈,实现5分钟部署、1核1G稳定运行、数据完全自主可控。
核心特性:AES-GCM-256字段级加密、异步邮件队列、多支付网关适配、Telegram/Bark实时推送,为每一位开发者提供安心稳定的发卡体验。
升级新版并保留订单、卡密、商品和配置,全程自动迁移表结构。
pm2 stop asolica-server$ 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
server/data 和 server/uploads,删除其他旧文件,上传新版源码$ bash install.sh $ pm2 restart asolica-server
启动时系统会自动执行数据库迁移,无需手动操作。跨大版本升级建议先在测试环境验证。
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 compose down -v $ rm -rf server/data server/uploads .env $ docker volume prune -f
重新初始化:
cp .env.example .env,编辑配置JWT_SECRET等参数docker compose up -d --buildcat server/data/admin_password.txt彻底清除旧数据,从零开始PM2部署。
$ pm2 stop asolica-server $ pm2 delete asolica-server $ pm2 save $ pkill -f "node.*app.js" || true
rm -rf /www/wwwroot/asolicass -tlnp | grep 3200(应无输出)bash install.sh,系统会自动生成新数据库和初始密码解决升级后仍显示旧版本/旧数据的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 + Vite | Composition API,Pinia状态管理,Vue Router |
| 后端 | Express.js | Node.js RESTful API,JWT鉴权 |
| 数据库 | SQLite (better-sqlite3) | WAL模式,单文件零配置 |
| 安全 | AES-GCM-256 + bcrypt | 字段级加密,密码强散列 |
| 校验 | Zod | 前后端统一Schema验证 |
架构分层:前端静态资源由Nginx托管,API请求反向代理到Express后端,SQLite本地文件存储,所有敏感数据AES加密后落库。
为什么选择SQLite而非MySQL?
Q: SQLite能支撑多少并发?
A: WAL模式下读写不互斥,单次查询<2ms,1核1G可支撑日均数千订单、600+TPS,完全满足中小规模发卡场景。
Q: 相比MySQL有什么优势?
A: 零配置、免运维、单文件备份迁移简单、无网络连接开销、内存占用极低(空载~28MB)。
Q: 什么时候需要换MySQL?
A: 日订单过万、多机分布式部署时再考虑迁移,Asolica当前版本专注SQLite极致优化。
核心数据备份方案与灾难恢复。
$ 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
$ node server/scripts/backup.js
$ sqlite3 server/data/asolica.db ".backup '/backup/asolica_$(date +%Y%m%d).db'"
停止服务 → 用备份覆盖 server/data、server/uploads、.env → 检查权限 chown -R www:www server/data → 重启服务验证。
配置Cron实现每日自动备份,保留7天。
#!/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"
$ 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 compose logs -f app $ docker compose logs --tail=100 app $ docker compose logs --since=1h app
$ pm2 logs asolica-server $ tail -f ~/.pm2/logs/asolica-server-error.log $ pm2 flush # 清空日志
$ 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-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)、磁盘空间、系统负载。
高并发场景优化配置。
PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;
PRAGMA cache_size = -20000; # 20MB缓存
PRAGMA busy_timeout = 5000;
PRAGMA temp_store = MEMORY;
编辑 ecosystem.config.cjs:
node_args: '--max-old-space-size=256',
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种驱动,异步队列发送。
# 驱动: 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 # 阿里云/腾讯云密钥配置略
MAIL_FROM_ADDRESS必须与SMTP_USER一致后台"系统设置"中点击"发送测试邮件"验证,数据库 email_queue 表可查看发送状态和失败原因。
支持彩虹易支付、虎皮椒,回调幂等校验防重复发卡。
https://你的域名/api/v1/payment/callback/epayhttps://你的域名/api/v1/payment/callback/xunhupayBASE_URL必须配置为https://开头的正式域名,配置错误将导致无法接收支付回调!
测试:创建0.01元测试商品下单支付,验证是否自动发卡、订单状态更新、邮件通知正常。
新订单、库存预警实时推送到手机。
/newbot创建Bot,获取Bot Tokenhttps://api.telegram.org/bot<TOKEN>/getUpdates 获取Chat IDhttps://api.day.app/xxxxx/)触发场景:新订单支付成功、库存不足预警、系统异常告警。
支持固定金额折扣和百分比折扣两种类型。
固定金额:直接减免指定金额(如满10减5);百分比折扣:按比例折扣(如8折设为0.8)。
后台营销→优惠券新建,填写优惠券码、折扣类型、有效期、适用商品、最大使用次数。买家结算页输入券码自动抵扣。
注意:单笔订单只能用一张券,过期/达次数上限自动失效。
支付网关强制要求HTTPS,两种配置方式。
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; }
隐藏版本、安全响应头、禁止敏感文件访问。
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步骤。
pm2 stop asolica-server 或 docker compose down$ openssl rand -hex 32
node server/scripts/reset-password.js最佳实践:用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实现中英双语,支持一键切换,浏览器语言自动检测,适配跨境销售场景。
数据目录文件用途说明。
| 文件 | 说明 |
|---|---|
asolica.db | 主数据库:商品、订单、卡密、用户、配置等所有核心数据 |
asolica.db-wal | WAL预写日志,运行时存在,正常关闭自动合并 |
asolica.db-shm | 共享内存索引,加速WAL并发访问 |
admin_password.txt | 初始管理员密码备份文件 |
注意:-wal和-shm是WAL模式正常文件,不要手动删除,否则可能数据损坏。
移动端白屏问题。
现象:电脑端正常,手机浏览器白屏,控制台报CORS/MIME错误。
原因:Nginx配置了过严的跨源隔离头(Cross-Origin-Opener-Policy、Cross-Origin-Embedder-Policy)。
宝塔网站配置文件中删除这两行响应头,重载Nginx。
找回或重置管理员密码。
现象:部署后忘记初始随机密码无法登录后台。
解决方法1:查看备份文件:
$ cat server/data/admin_password.txt
解决方法2:重置脚本:
$ node server/scripts/reset-password.js
支付成功但订单状态未更新。
现象:买家已付款,但订单仍显示"待支付",未发卡。
原因:支付平台异步回调被阻断或BASE_URL配置错误。
.env中BASE_URL为https://开头的正确域名/api/v1/payment/callback/*的POST请求防止.env、数据库被直接访问下载。
隐患:Nginx未配置过滤时,访问者可直接下载数据库和配置文件。
Nginx配置中添加:
location ~* \.(db|sqlite|log|env|txt|sh)$ { deny all; }
验证:访问/.env返回403。
PM2显示Errored或频繁重启。
现象:pm2 start后进程Errored,日志报better-sqlite3或ESM语法错误。
原因:Node.js版本过低(需v18+),或原生模块未重新编译。
bash install.shSQLITE_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
容器立即退出或反复Restarting。
诊断:先看日志docker compose logs app
ss -tlnp | grep 3200,停止占用进程或改端口chmod -R 755 server/data && chown -R 1000:1000 server/data买家收不到卡密邮件。
email_queue表failed记录的error_messageMAIL_FROM_ADDRESS与SMTP_USER必须一致