# 阿力科技 宝塔完整部署指南

> 本文档从零开始，一步一步指导你将源码部署到全新服务器。

---

## 一、服务器要求

| 项目 | 要求 | 说明 |
|------|------|------|
| **操作系统** | **Ubuntu 22.04 / 24.04 LTS (64位)** | ⚠ CentOS 7 不支持 APK 构建 |
| **架构** | x86_64 (AMD64) | 不支持 ARM |
| **CPU** | ≥ 1 核 | 构建 APK 时推荐 2 核 |
| **内存** | ≥ 2G | 构建 APK 需要较大内存 |
| **硬盘** | ≥ 20G | |
| **网络** | 有公网 IP + 已备案域名 | |

---

## 二、安装宝塔面板

SSH 登录服务器后执行：

```bash
wget -O install.sh https://download.bt.cn/install/install_lts.sh && sudo bash install.sh ed8484bec
```

安装完成后记下宝塔面板的：
- 面板地址
- 用户名
- 密码

---

## 三、安装运行环境

### 3.1 宝塔软件商店安装

| 软件 | 操作 |
|------|------|
| **Nginx** | 直接安装（默认版本即可） |
| **MySQL 5.7 或 8.0** | 直接安装 |
| **PHP 8.3** | 安装后需配置（见 3.2） |
| **PM2管理器** | 安装（用于管理 Node.js 进程） |

### 3.2 PHP 8.3 配置

**安装扩展**（宝塔 → 软件商店 → PHP-8.3 → 设置 → 安装扩展）：
- `fileinfo`
- 其他默认已安装：`pdo_mysql`、`openssl`、`mbstring`、`json`

**解禁函数**（宝塔 → PHP-8.3 → 设置 → 禁用函数）：

删除以下函数（如存在）：
- `putenv`
- `exec`
- `proc_open`（可选）

### 3.3 安装 Java JDK（APK 构建必需）

```bash
sudo apt update
sudo apt install -y openjdk-11-jdk
java -version  # 确认输出 openjdk 11.x
```

### 3.4 安装 .NET 8.0 Runtime（APK 构建必需）

```bash
sudo apt install -y dotnet-runtime-8.0
dotnet --list-runtimes  # 确认输出 Microsoft.NETCore.App 8.0.x
```

> 如果 `apt` 找不到 dotnet，先添加微软源：
> ```bash
> wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
> sudo dpkg -i packages-microsoft-prod.deb
> sudo apt update
> sudo apt install -y dotnet-runtime-8.0
> ```

### 3.5 安装 APK 构建工具（7z、zipalign）

```bash
sudo apt install -y p7zip-full zipalign
7z --help | head -2    # 确认 7z 可用
which zipalign         # 确认 zipalign 可用
```

### 3.6 PHP-FPM 超时配置

```bash
# 修改 PHP 超时设置（APK 构建需要较长时间）
sed -i 's/max_execution_time = .*/max_execution_time = 600/' /www/server/php/83/etc/php.ini
```

### 3.7 安装 Node.js（如 PM2 管理器未自带）

```bash
node -v  # PM2 管理器通常已安装 Node.js
# 如果没有，执行：
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs
```

---

## 四、创建网站和数据库

### 4.1 添加站点
宝塔 → 网站 → 添加站点：
- **域名**：填bb.6upw.com（如 `bb.6upw.com`）
- **PHP 版本**：选 `PHP-83`
- **创建数据库**：选 MySQL，记下**用户名**、**密码**、**数据库名**

### 4.2 导入数据库
宝塔 → 数据库 → 找到刚创建的数据库 → 导入 → 上传 `lingjie_db.sql` 并执行

### 4.3 创建管理员账号

在 phpMyAdmin 中执行（先在 SSH 中生成密码 hash）：

```bash
php -r "echo password_hash('你的密码', PASSWORD_DEFAULT);"
```

然后在 phpMyAdmin 中执行：

```sql
-- 后台管理员（/private/login.php）
UPDATE admins SET password = '上面输出的hash' WHERE username = 'admin';

-- 前端控制端管理员
INSERT INTO users (usrname, password, email, authorty, token, token_expiration, profilepic)
VALUES ('admin', '上面输出的hash', 'admin@bb.6upw.com', 'admin', '', NOW(), '');
```

---

## 五、上传源码

将 `tmp_dl_x9k2m` 目录下**所有文件**上传到网站根目录。

最终目录结构应为：

```
/www/wwwroot/bb.6upw.com/
├── api/
│   ├── ws/                  ← WebSocket 服务
│   │   ├── websocket-server.js
│   │   ├── package.json
│   │   └── node_modules/
│   ├── auth.php
│   ├── devices.php
│   └── ...
├── assets/                  ← 前端文件
├── private/
│   ├── EaodStarter          ← APK 构建程序
│   ├── build_api.php
│   ├── build_runner.php
│   ├── login.php            ← 后台入口
│   ├── apkstub/             ← APK 模板
│   │   ├── apkstub.zip
│   │   └── tools/apktool.jar
│   └── ...
├── user/                    ← 用户文件
├── .env                     ← ⚠ 必须修改
├── app.config.js            ← 已改好
└── index.html
```

**上传后清理（可选）：**
```bash
cd /www/wwwroot/bb.6upw.com
rm -rf private/Eaod_logs/* private/errors/* private/security_audit/*
```

---

## 六、修改 `.env` 配置文件

这是**唯一需要修改**的配置文件，用宝塔的文件管理器编辑：

```bash
# ============ 数据库（改成宝塔创建的） ============
DB_HOST=127.0.0.1
DB_USER=你的数据库用户名
DB_PASSWORD=你的数据库密码
DB_NAME=你的数据库名

# ============ 域名（改成bb.6upw.com） ============
WS_URL=wss://bb.6upw.com/api/ws/
WS_ALLOWED_ORIGINS=https://bb.6upw.com
CORS_ALLOWED_ORIGINS=https://bb.6upw.com
APP_DOMAIN=bb.6upw.com

# ============ 路径（改成宝塔路径） ============
APP_BASE_PATH=/www/wwwroot/bb.6upw.com
APK_STUB_PATH=/www/wwwroot/bb.6upw.com/private/apkstub/apkstub.zip

# ============ 以下不用改 ============
# SECRET_KEY, SECRET_IV, ADMIN_KEY 等保持不变
# WS_PORT=8080 保持不变
```

---

## 七、设置文件权限

```bash
# 网站目录权限
chattr -i /www/wwwroot/bb.6upw.com/.user.ini
chown -R www:www /www/wwwroot/bb.6upw.com/
chmod -R 755 /www/wwwroot/bb.6upw.com/

# 用户文件目录需要写权限
chmod -R 777 /www/wwwroot/bb.6upw.com/user/
chmod -R 777 /www/wwwroot/bb.6upw.com/private/Eaod_logs/
chmod -R 777 /www/wwwroot/bb.6upw.com/private/errors/
chmod -R 777 /www/wwwroot/bb.6upw.com/private/security_audit/

# EaodStarter 需要执行权限
chmod +x /www/wwwroot/bb.6upw.com/private/EaodStarter
```

---

## 八、配置 Nginx

宝塔 → 网站 → bb.6upw.com → 设置 → 配置文件 → **替换 `server{}` 块全部内容为：**

server
{
    listen 80;
    listen 443 ssl;
    listen 443 quic;
    http2 on;
    server_name sr.ldyku.shop;
    index index.html;
    root /www/wwwroot/sr.ldyku.shop;

    #CERT-APPLY-CHECK--START
    include /www/server/panel/vhost/nginx/well-known/sr.ldyku.shop.conf;
    #CERT-APPLY-CHECK--END

    include /www/server/panel/vhost/nginx/extension/sr.ldyku.shop/*.conf;

    #SSL-START SSL相关配置
    #error_page 404/404.html;
    #HTTP_TO_HTTPS_START
    set $isRedcert 1;
    if ($server_port != 443) {
        set $isRedcert 2;
    }
    if ( $uri ~ /\.well-known/ ) {
        set $isRedcert 1;
    }
    if ($isRedcert != 1) {
        rewrite ^(/.*)$ https://$host$1 permanent;
    }
    #HTTP_TO_HTTPS_END
    ssl_certificate    /www/server/panel/vhost/cert/sr.ldyku.shop/fullchain.pem;
    ssl_certificate_key    /www/server/panel/vhost/cert/sr.ldyku.shop/privkey.pem;
    ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_tickets on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    add_header Strict-Transport-Security "max-age=31536000";
    add_header Alt-Svc 'quic=":443"; h3=":443"; h3-29=":443"; h3-27=":443";h3-25=":443"; h3-T050=":443"; h3-Q050=":443";h3-Q049=":443";h3-Q048=":443"; h3-Q046=":443"; h3-Q043=":443"';
    error_page 497  https://$host$request_uri;

    #SSL-END

    client_max_body_size 10m;
    server_tokens off;
    add_header X-Content-Type-Options nosniff always;
    add_header X-Frame-Options DENY always;
    add_header Referrer-Policy strict-origin-when-cross-origin always;

    # 错误页
    error_page 400 401 403 404 405 500 502 503 504 /error.html;
    location = /error.html {
        internal;
        return 200 '<!DOCTYPE html><html><body><p>Request error</p></body></html>';
        add_header Content-Type text/html;
    }

    # 屏蔽扫描
    location ~* ^/(wp-admin|wp-login|wp-content|wordpress|phpmyadmin|adminer) {
        return 444;
    }

    # 私有 PHP 接口
    location ~ ^/private/(profile_api|build_api|inventory_api|login|logout|createacc|create|session_check|cb_custom|cb_store)\.php$ {
        include enable-php-83.conf;
    }

    # 静态资源
    location ~ ^/user/storage/ { expires 7d; try_files $uri =404; }
    location ~ ^/user/ui/ { expires 7d; try_files $uri =404; }
    location ~ ^/user/apps/.*\.apk$ { expires 1d; try_files $uri =404; }
    location ~* ^/user/ { deny all; return 404; }

    # 敏感目录/文件
    location ~* ^/(private|configs|vendor|logs|scripts|deploy|store|node_modules)/ {
        deny all; return 404;
    }
    location ~ /\. { deny all; return 404; }
    location ~* \.(env|ini|log|sql|bak|sh|json|md|yml|xml|key|crt)$ {
        deny all; return 404;
    }

    # API 接口（已添加 settings 到白名单）
    location ~ ^/api/(auth|devices|detail|assign|remove|toggle|sync|report|Ping|Error|settings)\.php$ {
        include enable-php-83.conf;
    }
    location ~ ^/api/.*\.php$ { return 404; }

    # WebSocket 反向代理
    location /api/ws/ {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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_read_timeout 3600s;
        proxy_send_timeout 3600s;
        proxy_pass http://127.0.0.1:8080;
    }

    # 前端 SPA
    location / {
        try_files $uri $uri/ /index.html;
    }

    # PHP 兜底
    location ~ \.php$ {
        include enable-php-83.conf;
    }

    # SSL 证书验证
    location ~ \.well-known {
        allow all;
    }

    # UA 拦截
    if ($http_user_agent ~* (nmap|sqlmap|masscan|zgrab|censys|shodan)) {
        return 444;
    }

    access_log /www/wwwlogs/sr.ldyku.shop.log;
    error_log /www/wwwlogs/sr.ldyku.shop.error.log;
}



> ⚠ 以上配置已填好 `bb.6upw.com`，可直接使用

---

## 九、启动 WebSocket 服务

宝塔 → PM2管理器 → 添加项目：
- **启动文件**：`/www/wwwroot/bb.6upw.com/api/ws/websocket-server.js`
- **项目名称**：`lingjie-ws`
- **运行目录**：`/www/wwwroot/bb.6upw.com/api/ws`

添加后确认状态为「运行中」。

---

## 十、申请 SSL 证书

宝塔 → 网站 → bb.6upw.com → 设置 → SSL → Let's Encrypt → 申请

申请成功后宝塔会自动在 `#SSL-START` 和 `#SSL-END` 之间插入证书配置。

---

## 十一、验证清单

| # | 检查项 | 方法 | 预期结果 |
|---|--------|------|----------|
| 1 | 网站打开 | 浏览器访问 `https://bb.6upw.com` | 显示登录页面 |
| 2 | 前端登录 | 用 admin 账号登录 | 进入控制端 |
| 3 | 设备列表 | 登录后查看设备列表 | 正常显示 |
| 4 | WebSocket | F12 → 网络 → 看 `/api/ws/` | 状态 101 |
| 5 | 后台管理 | 访问 `/private/login.php` | 显示门禁密钥输入页 |
| 6 | APK 构建 | 在控制端尝试构建 APK | 构建成功 |
| 7 | Java 环境 | SSH 执行 `java -version` | 输出 openjdk 11.x |
| 8 | .NET 环境 | SSH 执行 `dotnet --list-runtimes` | 输出 8.0.x |
| 9 | 无弹窗 | 页面停留 1 分钟 | 没有反复弹 "服务连接就绪" |

---

## 附：后台管理入口

| 入口 | 地址 | 说明 |
|------|------|------|
| 前端控制端 | `https://bb.6upw.com` | 管理设备、构建 APK |
| 后台管理 | `https://bb.6upw.com/private/login.php` | 账号管理 |
| 门禁密钥 | `.env` 中的 `ADMIN_PANEL_ACCESS_KEY` | 进入后台前需输入 |

---

## 附：已修改的源码文件（无需再改）

| 文件 | 改动 |
|------|------|
| `app.config.js` | 品牌名 → 阿力科技 + WebSocket 重连节流 |
| `private/build_api.php` | 硬编码路径 → `APP_BASE_PATH` 动态读取 |

---

## 附：修改管理员密码

**第一步：生成密码 hash**

```bash
php -r "echo password_hash('你的新密码', PASSWORD_DEFAULT);"
```

复制输出的 hash 字符串。

**第二步：更新数据库**

```bash
DB_USER=$(grep DB_USER /www/wwwroot/bb.6upw.com/.env | cut -d= -f2)
DB_PASS=$(grep DB_PASSWORD /www/wwwroot/bb.6upw.com/.env | cut -d= -f2)
DB_NAME=$(grep DB_NAME /www/wwwroot/bb.6upw.com/.env | cut -d= -f2)

# 修改前端控制面板密码（登录页面）
mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "UPDATE users SET password='生成的hash' WHERE usrname='admin';"

# 修改后台管理密码（/private/login.php）
mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "UPDATE admins SET password='生成的hash' WHERE username='admin';"
```

> 将命令中的 `你的新密码` 和 `生成的hash` 替换为实际值。
