Files
LocalNav/部署与使用说明.md
T
dekun fd5e333daf feat: 服务管理支持 HTTP/HTTPS 协议选择
- Service 增加 scheme 字段,build_url 按协议拼接地址
- 表单新增协议下拉;启动时自动迁移已有 SQLite 库
- 更新部署说明中的 HTTPS 服务添加示例

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 11:37:32 +08:00

571 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 本地导航站 · 部署与使用说明
本文档为 **中文说明****部署操作** 合一版本,适用于在局域网或 **外网 HTTPS** 场景下自建使用。
**代码仓库:** https://git.bz121.com/dekun/LocalNav.git
---
## 一、项目概述
**本地导航站**是一个基于 **Flask** 的轻量 Web 应用,用于把多台内网机器、多个带端口的本地服务(宝塔、AI 面板、路由管理页、各类后端控制台等)**收纳到同一个入口地址**。
- 浏览器打开一个网址即可进入。
- 左侧为 **自定义分组 + 服务链接列表**
- 右侧为 **大尺寸 iframe**:点击左侧链接时,在页面内嵌打开对应 `http://内网IP:端口/路径`,**不整页跳转、不新开标签**(体验类似统一后台)。
数据全部落在本机 **SQLite** 文件中,无需安装 MySQL,适合个人或小范围内网使用。
---
## 二、功能特性
| 模块 | 说明 |
|------|------|
| 账号登录 | 用户名 + 密码,会话由 Flask-Login 管理;表单带 CSRF 防护。 |
| 导航首页 | 左右分栏;左侧分组与服务;右侧 iframe 内嵌打开目标页。 |
| 分组管理 | 新增 / 编辑 / 删除分组;支持排序字段(数字越小越靠前)。 |
| 服务管理 | 新增 / 编辑 / 删除服务;字段:名称、内网主机、端口、路径、所属分组、排序。 |
| 数据库 | SQLite,默认文件名为 `nav_local.db`(与运行当前工作目录有关)。 |
| 网络监听 | 默认绑定 `0.0.0.0`,便于同局域网手机、电脑访问。 |
**说明**:服务访问地址由程序拼接为 `{scheme}://{host}:{port}{path}`,可在「服务管理」中选择 **HTTP****HTTPS**。嵌入 iframe 时浏览器仍按混合内容等安全策略校验(例如导航站为 HTTPS、内嵌目标为 HTTP 时可能被浏览器拦截)。
---
## 三、技术栈与运行要求
- **Python**:建议 **3.10+**(3.9 一般也可,未在全部小版本上逐一验证)。
- **主要依赖**Flask、Flask-SQLAlchemy、Flask-Login、Flask-WTF、WTForms、Werkzeug。
- **浏览器**:现代浏览器(Chrome / Edge / Firefox / Safari 等)。
---
## 四、目录结构(参考)
```
本地导航/
├── app.py # 应用入口、路由、启动参数
├── models.py # 数据模型(用户、分组、服务)
├── forms.py # 表单定义
├── requirements.txt # Python 依赖列表
├── .env.example # 环境变量模板(复制为 .env 后修改)
├── .env # 本地配置(自建,勿提交 Git)
├── ecosystem.config.cjs # PM2 守护进程配置
├── nav_local.db # SQLite 数据库(首次成功运行后生成,勿手误提交到公开仓库)
├── static/
│ └── style.css # 样式
└── templates/ # Jinja2 模板(登录、首页、后台页)
├── base.html
├── login.html
├── index.html
├── admin_groups.html
├── admin_group_form.html
├── admin_services.html
└── admin_service_form.html
```
---
## 五、环境变量与 `.env` 文件
程序启动时会从 **与 `app.py` 同目录**`.env` 文件加载变量(依赖 `python-dotenv`)。**若 `.env` 不存在则跳过,不影响启动。**
**优先级**:操作系统或进程里 **已经设置** 的环境变量 **优先**`.env` 中的键 **不会覆盖** 已有变量(与 `python-dotenv` 默认行为一致)。便于在 systemd 里写死 `NAV_SECRET_KEY`,本地开发仍用 `.env` 填其他项。
**初次使用:**
```bash
cp .env.example .env
# 编辑 .env,至少设置 NAV_SECRET_KEY(长期运行强烈建议)
```
`.env` 含敏感信息,已列入 `.gitignore`,请勿提交到公开仓库;仓库内仅保留 **`.env.example`** 作模板。
### 5.1 变量一览
| 变量名 | 含义 | 默认值 |
|--------|------|--------|
| `NAV_SECRET_KEY` | Flask 会话、CSRF 等加密签名密钥。**生产或长期运行务必设置固定值**,否则重启后会话失效且安全性下降。 | 未设置时每次进程启动随机生成 |
| `NAV_DATABASE_URL` | SQLAlchemy 数据库连接串 | `sqlite:///nav_local.db` |
| `NAV_HOST` | `python app.py` 时监听地址 | `0.0.0.0` |
| `NAV_PORT` | `python app.py` 时监听端口 | `5070` |
| `NAV_DEBUG` | 是否开启调试模式(**勿**在内网多人共用服务器上长期开启) | 未设置或不为 `1` 则为关闭;设为 `1` 开启 |
**生成密钥示例(Linux / macOS):**
```bash
export NAV_SECRET_KEY="$(openssl rand -hex 32)"
```
**Windows PowerShell 示例:**
```powershell
$env:NAV_SECRET_KEY = -join ((48..57) + (65..90) + (97..122) | Get-Random -Count 48 | ForEach-Object {[char]$_})
```
---
## 六、安装与运行(通用)
### 6.1 获取代码
**Git 克隆(推荐):**
```bash
git clone https://git.bz121.com/dekun/LocalNav.git
cd LocalNav
```
也可将项目目录放到目标机器上(拷贝、压缩包解压等)。下文以项目根目录为当前工作目录。
### 6.2 创建虚拟环境并安装依赖
**Linux / macOS**
```bash
cd /path/to/本地导航
python3 -m venv .venv
source .venv/bin/activate
pip install -U pip
pip install -r requirements.txt
```
**WindowsPowerShell):**
```powershell
cd C:\path\to\本地导航
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -U pip
pip install -r requirements.txt
```
**若 `pip install` 报错 “No matching distribution” 或版本列表为空**:多为镜像源未同步或网络策略问题,可显式指定官方索引:
```bash
pip install -r requirements.txt -i https://pypi.org/simple
```
### 6.3 直接启动(开发 / 小范围内网)
若已用 `.env` 配置 `NAV_SECRET_KEY` 等,可直接:
```bash
python app.py
```
否则可临时用环境变量(与 `.env` 二选一或混用,见上文优先级):
```bash
export NAV_SECRET_KEY="$(openssl rand -hex 32)" # Linux;长期部署也可写进 systemd 的 EnvironmentFile
python app.py
```
默认监听 **`http://0.0.0.0:5070`**。在同一局域网内的其他设备浏览器访问:
```text
http://<本机局域网IP>:5070
```
例如:`http://192.168.1.100:5070`
**注意**:内置的 `app.run()` 为 Flask 开发用服务器,**并发能力与健壮性有限**,适合个人使用或低并发内网场景。需要长期开机、略高并发时,建议使用下文 **Gunicorn** 方式。
---
## 七、首次登录与默认账号
1. 第一次成功启动且数据库中 **没有任何用户** 时,程序会自动创建:
- 用户:**`admin`**
- 密码:**`admin123`**
- 一个名为 **「默认分组」** 的空分组。
2. 控制台会打印一行提示(内容大意:默认账号仅内网使用,请尽快修改)。
**安全建议(强烈)**
- 首次登录后,尽快通过可靠方式修改密码。当前版本未内置「改密页」,可自行选用其一:
- 使用 [DB Browser for SQLite](https://sqlitebrowser.org/) 等工具打开 `nav_local.db`,删除 `users` 表中对应用户后,临时改代码跑一次初始化(不推荐反复操作);
- 或自行增加「修改密码」路由(二次开发)。
- **不要将**带默认口令的数据库文件提交到公开 Git 仓库。
- 本应用设计为 **内网聚合入口**;若需外网访问,请按 **9.8** 配置 HTTPS 与反向代理,勿将 `5070` 端口裸奔到公网。
---
## 八、使用说明(操作层面)
### 8.1 登录
访问站点根路径,未登录会跳转至 **`/login`**,输入用户名与密码即可。
### 8.2 导航首页(`/`
- **左侧**:按分组展示服务名称;点击后在 **右侧 iframe** 打开对应地址。
- **顶部**:可进入「分组管理」「服务管理」或退出登录。
- **内嵌页工具栏**:「刷新」为普通刷新(追加时间戳参数);「强制刷新」等同 **Ctrl+F5**,先清空 iframe 再带随机参数重新加载,尽量跳过浏览器缓存(跨域 iframe 时效果取决于目标站点策略)。
### 8.3 分组管理(`/admin/groups`
- **新建 / 编辑**:填写分组名称、排序。
- **删除**:会 **同时删除** 该分组下的 **所有服务**(级联删除),请谨慎操作。
- 列表中可从某分组快捷 **「在此分组添加服务」**。
### 8.4 服务管理(`/admin/services`
- 字段含义简要说明:
- **服务名称**:左侧显示名称。
- **协议****HTTP** 或 **HTTPS**HTTPS 站点选 HTTPS,端口一般填 `443`(或其它 TLS 端口)。
- **主机或域名**:如 `192.168.1.10``api.example.com` 等。
- **端口**165535。
- **路径**:可选,须以 `/` 开头;留空则按 `/` 处理。
- **分组**:必选。
- **排序**:同分组内数字越小越靠前。
**HTTPS 服务示例:**
| 字段 | 示例值 |
|------|--------|
| 协议 | HTTPS |
| 主机或域名 | `panel.example.com` |
| 端口 | `443` |
| 路径 | `/` |
生成地址:`https://panel.example.com:443/`
### 8.5 关于 iframe 打不开的说明
部分网站(尤其银行、部分管理面板)通过 **`X-Frame-Options`** 或 **`Content-Security-Policy`** 禁止被嵌入 iframe,此时右侧区域可能为空白或浏览器控制台报错。这属于 **目标站点安全策略**,与本导航站实现无关。若必须统一入口,只能由目标服务侧放开嵌入策略,或改为新窗口打开(需改代码,非当前默认行为)。
---
## 九、部署指南(以 Ubuntu 为例)
以下假设:系统为 **Ubuntu 20.04/22.04/24.04** 等,项目路径为 **`/opt/LocalNav`**,监听端口 **5070**,进程以 **root** 用户运行;可根据实际域名与端口修改。
### 9.1 系统准备
```bash
sudo apt update
sudo apt install -y python3 python3-venv python3-pip git
```
(若已安装 Python 3、venv 与 git,可跳过。)
### 9.2 克隆项目并安装依赖
```bash
sudo mkdir -p /opt
cd /opt
sudo git clone https://git.bz121.com/dekun/LocalNav.git
cd /opt/LocalNav
python3 -m venv .venv
source .venv/bin/activate
pip install -U pip
pip install -r requirements.txt -i https://pypi.org/simple
```
后续更新代码:
```bash
cd /opt/LocalNav
git pull
source .venv/bin/activate
pip install -r requirements.txt -i https://pypi.org/simple
sudo systemctl restart nav-site
```
### 9.3 配置密钥(必做)
```bash
sudo mkdir -p /etc/nav-site
sudo bash -c 'openssl rand -hex 32 > /etc/nav-site/secret_key'
sudo chmod 600 /etc/nav-site/secret_key
```
后续由 systemd 读取该文件并注入 `NAV_SECRET_KEY`(见下节)。
**替代做法**:也可在项目根目录放置 `.env`(建议 `chmod 600 .env`),`WorkingDirectory` 指向项目根时程序会自动加载。若 systemd 的 `Environment` / `EnvironmentFile` 里已设置同名变量,**以 systemd 为准**`.env` 不会覆盖已有环境变量)。
### 9.4 使用 systemd 常驻运行(推荐)
创建服务文件(仍使用内置 `python app.py` 时示例;若改用 Gunicorn,将 `ExecStart` 改为 gunicorn 命令即可):
```bash
sudo nano /etc/systemd/system/nav-site.service
```
示例内容(**root 运行**):
```ini
[Unit]
Description=Local Nav Flask Site
After=network.target
[Service]
Type=simple
User=root
Group=root
WorkingDirectory=/opt/LocalNav
EnvironmentFile=-/etc/nav-site/env
ExecStart=/opt/LocalNav/.venv/bin/python /opt/LocalNav/app.py
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
```
创建环境文件 `/etc/nav-site/env`**不要**把密钥写进 Git):
```bash
sudo nano /etc/nav-site/env
```
示例:
```ini
NAV_SECRET_KEY=粘贴openssl_rand_hex32的输出
NAV_HOST=0.0.0.0
NAV_PORT=5070
```
启用并启动:
```bash
sudo systemctl daemon-reload
sudo systemctl enable nav-site
sudo systemctl start nav-site
sudo systemctl status nav-site
```
查看日志:
```bash
journalctl -u nav-site -f
```
### 9.5 防火墙(若启用了 ufw
```bash
sudo ufw allow 5070/tcp
sudo ufw reload
```
仅内网使用时,也可限制来源网段(示例,请按实际修改):
```bash
sudo ufw allow from 192.168.0.0/16 to any port 5070 proto tcp
```
### 9.6 可选:使用 Gunicorn 提高稳定性
安装:
```bash
source /opt/LocalNav/.venv/bin/activate
pip install gunicorn
```
`WorkingDirectory` 仍为项目根目录,**保证 `nav_local.db` 路径与工作目录一致**。示例 `ExecStart`
```ini
ExecStart=/opt/LocalNav/.venv/bin/gunicorn -w 2 -b 0.0.0.0:5070 app:app
```
说明:`-w 2` 为 worker 数量,可按机器 CPU 调整;`app:app` 表示 `app.py` 中的全局变量 `app`
### 9.7 使用 PM2 守护进程(可选)
适合已安装 [PM2](https://pm2.keymetrics.io/) 的环境(常见于用 Node 的服务器上顺带托管 Python 进程)。项目根目录提供 **`ecosystem.config.cjs`**,用虚拟环境里的 Python 直接运行 **`app.py`**(与手动 `python app.py` 一致),**实例数固定为 1**(Flask 内置开发服务器不宜多进程监听同一端口)。
**1. 安装 PM2(若尚未安装,需本机已有 Node.js / npm**
```bash
sudo npm install -g pm2
```
**2. 准备虚拟环境与依赖(项目根目录)**
```bash
cd /opt/LocalNav # 项目路径
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt -i https://pypi.org/simple
cp -n .env.example .env && nano .env # 至少配置 NAV_SECRET_KEY、NAV_PORT=5070
```
**3. 启动 / 查看 / 维护**
```bash
cd /opt/LocalNav
pm2 start ecosystem.config.cjs
pm2 status
pm2 logs nav-site
```
日志文件默认写入项目下 **`logs/`** 目录(PM2 会自动创建;该目录已加入 `.gitignore`)。
**4. 开机自启(在目标机器上执行一次)**
```bash
pm2 save
pm2 startup
# 按终端里打印的 sudo 命令整行复制执行,再执行一次 pm2 save
```
**5. 常用命令**
| 命令 | 作用 |
|------|------|
| `pm2 restart nav-site` | 热重启(改代码或 .env 后) |
| `pm2 stop nav-site` | 停止 |
| `pm2 delete nav-site` | 从 PM2 列表移除 |
| `pm2 monit` | 简易监控 |
**说明**:若 `interpreter` 指向的 `.venv/bin/python` 不存在,PM2 会启动失败;请确认虚拟环境路径与 `ecosystem.config.cjs` 中一致。Windows 下脚本会自动使用 `.venv\Scripts\python.exe`
### 9.8 外网 HTTPS 访问(Nginx 反向代理)
若需从 **公网或外网** 通过 **HTTPS** 访问本导航站(浏览器地址栏为 `https://`),建议在 Ubuntu 上用 **Nginx** 终止 TLS,反代到本机 `127.0.0.1:5070`。Flask 仍监听内网端口,不直接暴露 5070 到公网。
**1. 安装 Nginx 与 CertbotLet's Encrypt 免费证书,需已解析到本机的域名)**
```bash
sudo apt install -y nginx certbot python3-certbot-nginx
```
**2. 调整应用环境变量**
编辑 `/etc/nav-site/env`(或项目根目录 `.env`),增加:
```ini
NAV_TRUST_PROXY=1
NAV_SESSION_COOKIE_SECURE=1
NAV_CSRF_TRUSTED_ORIGINS=https://你的域名
```
保存后重启:`sudo systemctl restart nav-site`
**3. Nginx 站点配置**
`nav.example.com` 替换为你的域名:
```bash
sudo nano /etc/nginx/sites-available/localnav
```
```nginx
server {
listen 80;
server_name nav.example.com;
location / {
proxy_pass http://127.0.0.1:5070;
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_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_read_timeout 300s;
}
}
```
启用并重载:
```bash
sudo ln -sf /etc/nginx/sites-available/localnav /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
```
**4. 申请 HTTPS 证书**
```bash
sudo certbot --nginx -d nav.example.com
```
按提示完成验证后,Certbot 会自动配置 `listen 443 ssl` 与证书路径。证书续期一般已由系统定时任务处理,可手动验证:
```bash
sudo certbot renew --dry-run
```
**5. 防火墙**
```bash
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# 若仅通过 Nginx 对外,可不放行 5070 到公网
sudo ufw reload
```
**6. 访问**
外网浏览器打开:`https://nav.example.com`
**说明:**
- 内嵌 iframe 中的目标服务仍为你在「服务管理」里填写的 `http://内网IP:端口`;外网用户能否打开取决于目标服务是否可从其网络访问,与本导航站 HTTPS 无关。
- 若无公网域名,仅有公网 IP,可改用 **自签证书****Caddy**`caddy reverse-proxy --from :443 --to 127.0.0.1:5070`),但浏览器会提示证书不受信任,需自行导入信任。
- 公网暴露登录入口存在安全风险,请务必使用强密码,并考虑 IP 白名单、VPN 或 Nginx `allow/deny` 等额外访问控制。
---
## 十、数据与备份
- 默认数据库文件:**`nav_local.db`**,位于 **启动进程时的当前工作目录**(与 `WorkingDirectory` 一致)。
- 备份:定期复制该文件即可(建议在服务停止或负载极低时复制,避免损坏)。
- 恢复:替换同名文件后重启服务。
---
## 十一、路由一览(便于排障与二次开发)
| 路径 | 说明 |
|------|------|
| `/` | 导航首页(需登录) |
| `/login` | 登录页 |
| `/logout` | 退出登录 |
| `/admin/groups` | 分组列表 |
| `/admin/groups/new` | 新建分组 |
| `/admin/groups/<id>/edit` | 编辑分组 |
| `/admin/groups/<id>/delete` | 删除分组(POST |
| `/admin/services` | 服务列表(支持 `?group_id=` 筛选) |
| `/admin/services/new` | 新建服务 |
| `/admin/services/<id>/edit` | 编辑服务 |
| `/admin/services/<id>/delete` | 删除服务(POST |
---
## 十二、常见问题(FAQ
**Q:手机能打开吗?**
能。只要手机与服务器在同一局域网,且防火墙放行端口,浏览器访问 `http://服务器IP:端口` 即可。
**Q:为什么右侧 iframe 是白的?**
常见原因:目标站禁止被嵌入;目标服务宕机或地址/端口填错;浏览器混合内容策略(本应用为 HTTP 打开链接,若目标强制 HTTPS 且策略严格,可能异常)。可在新标签直接打开同一 URL 对比排查。
**Q:端口想改成其他值?**
设置环境变量 `NAV_PORT=8080`(示例)后重启进程;防火墙与 Nginx `proxy_pass` 端口需一并修改。默认端口为 **5070**
**Q:忘记密码怎么办?**
若有服务器文件权限,可用 SQLite 工具修改 `users` 表,或删除用户行后通过代码逻辑重新种子用户(需具备运维或开发能力)。
**Q:能否从外网访问?**
可以。推荐在 Ubuntu 上用 **Nginx + HTTPS** 反代到 `127.0.0.1:5070`,并配置 `NAV_TRUST_PROXY=1` 等变量,详见 **9.8 外网 HTTPS 访问**。请务必使用强密码并做好访问控制。
---
## 十三、版本与维护
- 依赖版本见 `requirements.txt`;升级依赖前建议在测试环境验证。
- 修改模板或静态文件后,重启进程即可生效;修改 Python 代码同样需要重启(`NAV_DEBUG=1` 时开发服务器可自动重载,但不建议在生产长期开启)。
---
**文档结束。** 若你后续增加「HTTPS 链接」「新窗口打开」「修改密码」等功能,建议在本文档对应章节补充说明并保持与代码一致。
**仓库地址:** https://git.bz121.com/dekun/LocalNav.git