Drouter 是一套跑在 Debian 13 (trixie) 上的软路由管理系统。它提供了 43 个功能页面的 Web 面板,覆盖一台家用 / 小型办公路由器需要的一切:WAN 接入、PPPoE 多拨、DHCP/DNS、IPv6、防火墙、QoS 限速、访问控制、DDNS、文件共享、Docker 管理……
但它的核心设计目标和别人不一样:
它不重新实现任何协议。
PPPoE 交给 ppp,DHCP 交给 dnsmasq,IPv6 RA 交给 radvd,NAT 交给 nftables,时间同步交给 chrony。
Web 面板只做三件事:渲染原生配置文件 → 语法预检 → 原子写入并 reload。
这样做的好处是,你的路由器上跑的永远是发行版维护的、有安全更新的上游服务, 而不是某个"自己写了一套 DHCP 服务端"的黑盒。面板哪天不想要了,删掉它, 系统仍是一台配置完好的 Debian 路由器。
| Drouter | OpenWrt | RouterOS | |
|---|---|---|---|
| 底座 | 原版 Debian 13 | 自建发行版 | 自有内核 |
| 包管理 | apt(25,000+ 包直接可用) |
opkg(软件包有限) |
无 |
| 配置来源 | 原生服务配置文件(可读可改) | UCI 数据库 | 二进制配置 |
| 进系统的方式 | SSH / 本地桌面 / Web | SSH / LuCI | WinBox |
| Docker | 原生 docker.io |
需自建,限制多 | 容器支持受限 |
| 适合谁 | 有 Linux 基础、想要可审计可迁移 | 想要开箱即用 | 想要稳定商用 |
这是整个项目的第一原则,也是最花功夫的部分。
装完 Drouter,你的网络不会有任何变化:
ip_forward仍是0—— 不做路由转发- 默认网关仍是原来的 —— 不抢网关
dnsmasq/radvd/kea不会被启动 —— 不抢 53 / 67 / 547 端口nftables规则集为空 —— 不动防火墙
你可以在一台正在被使用的机器上装它、慢慢配它、反复预览渲染结果, 直到某个你准备好的时刻,才让它真正生效。
所有会改变网络状态的动作,都遵循同一条链路:
配置入库 → 渲染预览(看清会写出什么) → 语法预检 → 自动快照 → 原子写入 → reload
↑ ↑
这一步就可以停下来 出问题一键回滚
为什么坚持这个设计? 因为我见过太多"装个软路由结果全家断网、还得摸黑进机房"的事故。 一台路由器大半时间里是家里的唯一网络出口 —— 它不该有"试试看"这种操作。
- 渲染预览:保存前能看到渲染出的真实配置文件内容,不是"相信系统会处理"
- 依赖自检:43 项功能依赖逐个探测,缺什么、装什么、影响哪个功能,一目了然
- 实时监控:CPU / 内存 / 磁盘 / 进程 / 网速 / 延迟 / 抖动,2 秒刷新
- 统一日志:系统日志、防火墙日志(IPv4+IPv6)、连接跟踪流日志、PPPoE 拨号日志集中可查
- 保存 ≠ 应用:改配置和让它生效是两个按钮,中间隔着一次确认
| 指标 | 数值 |
|---|---|
| 后端常驻内存 | < 25 MB |
| 依赖 | Python 3 标准库(http.server + ssl + sqlite3) |
| 前端构建 | 无(原生 HTML/CSS/JS,改完刷新即可) |
| npm / node_modules | 零 |
| 首次启动到可用 | < 3 秒 |
没有 Flask、没有 FastAPI、没有 gunicorn、没有 Redis、没有 Node 运行时。 一台 2 核 4 GB 内存的小主机,内存几乎全能留给 PPPoE 转发和 Docker —— 本项目全部开发与实测都在这样一台机器上完成,这是参考环境,不是准入门槛: 最低 1 核 1 GB 就能起来,详见推荐配置。
所有配置都存在 SQLite 里,但SQLite 不是唯一配置源:
每次「应用」都会渲染出真正的原生配置文件落盘。
这意味着——把面板删掉,配置还在;把 /etc 打包拷到另一台 Debian,直接就能用。
没有"只有它自己看得懂的配置格式"这种锁定。
- 快照回滚:每次应用前自动快照,出问题回退到上一个已知良好状态
- 紧急救援通道:
drouter-rescue提供独立于主配置的最小网络恢复(默认关闭,可一键启用) - 构建保护模式:
/etc/drouter/BUILD_MODE存在时,后端拒绝一切改网络 / 抢端口的动作
第三点是给"在正在使用的机器上装机"这个场景准备的 —— 装的时候保护,配好了再解除。
以下全部是真实运行界面的截图(不是效果图),取自一台 2 核 4 GB 内存的 Debian 13 虚拟机。 共 78 张,按功能分组放在折叠块里 —— 点开对应分组即可查看。
③ 接口 —— 9 张
![]() 网卡与桥接 |
![]() WAN 口 · 接入方式 |
![]() WAN 口 · 实时状态 |
![]() WAN 口 · 拨号日志 |
![]() PPPoE 多拨 |
![]() PPPoE · 会话状态 |
![]() LAN 口 |
![]() VLAN / IPTV 单线复用 |
![]() 网络唤醒 WOL |
④ 寻址与路由 —— 12 张
![]() DHCP 服务 |
![]() DHCP · 租约表 |
![]() DNS 服务 |
![]() IPv6 / RA |
![]() IPv6 / RA · 前缀与 RDNSS |
![]() IPv6 / RA · 运行状态 |
![]() DHCPv6 / 前缀委派 |
![]() 动态域名 DDNS |
![]() DDNS · IPv6 记录 |
![]() DDNS · 解析结果 |
![]() 真·公网 IP 判定 |
![]() 真·公网 IP · NAT 类型 |
⑤ 安全 —— 7 张
![]() 防火墙 IPv4 |
![]() 防火墙 IPv4 · 规则与日志 |
![]() 防火墙 IPv6 |
![]() 防火墙 IPv6 · 规则与日志 |
![]() 端口转发 / DMZ |
![]() UPnP / NAT-PMP |
![]() 访问控制 / 时间组 |
⑥ 服务 —— 14 张
![]() 智能限速 QoS |
![]() QoS · 队列与规则 |
![]() 应用识别 DPI |
![]() DPI · 识别结果 |
![]() NTP 时间同步 |
![]() 文件共享 SMB / NFS |
![]() 文件共享 · 共享目录 |
![]() 打印服务 CUPS |
![]() 打印服务 · 打印队列 |
![]() 打印服务 · USB 直通 |
![]() 打印服务 · 共享设置 |
![]() AC / AP 管理中心 |
![]() AC / AP · 无线与 VLAN |
⑦ 工具 —— 11 张
![]() Web 终端 / 文件 |
![]() 通用 API 接口 |
![]() 通用 API · OpenAPI 文档 |
![]() 网络诊断工具 |
![]() IPv6 连通性测试 |
![]() Docker / Compose |
![]() Docker · 容器与镜像 |
![]() Docker · Compose 项目 |
![]() Docker 引擎配置 |
![]() Docker 引擎 · 镜像源测速 |
![]() Docker 引擎 · daemon.json |
⑨ 系统 —— 15 张
![]() 依赖自检与安装 |
![]() 依赖自检 · 探测结果 |
![]() 磁盘与日志清理 |
![]() 磁盘清理 · 占用明细 |
![]() 内核转发与加速 |
![]() 内核转发 · 开关与联动 |
![]() 证书 / SSL |
![]() 证书 / SSL · 签发与部署 |
![]() 证书 / SSL · 握手体检 |
![]() 电源控制 |
![]() 用户与密钥 |
![]() 用户与密钥 · SSH 公钥 |
![]() 系统设置 |
![]() 系统设置 · 时区与主机名 |
![]() 系统设置 · Web 端口 |
![]() 系统设置 · 审计日志 |
关于截图本身(点开)
- 原始分辨率 1272 × 900(「Web 终端 / 文件」一张为 1280 × 1024),未做压缩裁剪
- 仓库里以 ASCII 文件名入库(
docs/screenshots/02-overview.jpg这种), 避免中文名 +&在 URL 编码、CI、shell 里反复出问题 - 图片版权随项目走 MIT,可以自由用于介绍 / 二次分发
- 想自己重拍:登录后按
F11全屏,把窗口拉到 1272px 宽,按本文档的分组顺序截,存成同名文件覆盖即可
还没截图的 3 个页面
43 个功能页里已有 40 个配了截图,还剩 3 个欢迎补充:
| 功能页 | 说明 |
|---|---|
| 新手向导 | 四步配网(外网 → 内网 → DNS → IPv6),新手第一眼就会看到,优先级最高 |
| 主题之家 | Web 主题设计与离线预览 |
| 升级与保护 | 系统升级 + 构建保护模式开关 |
补图流程:
# 1. 把截图放进 docs/screenshots/,按现有命名规则编号
# 例如 02-wizard.jpg / 09-theme.jpg / 09-upgrade.jpg
# 2. 在 README「完整图集」对应分组的折叠块里加一行
# 3. 跑一下覆盖度检查,确认没有漏登记
python3 devtools/check-shots.py43 个功能页面,分 8 组。
| 页面 | 做什么 |
|---|---|
| 新手向导 | 四个步骤把一台裸 Debian 配成能上网的路由器:外网 → 内网 → DNS → IPv6,每步都有独立可读的成败结论 |
| 系统概览 | 硬件仪表盘(CPU / 内存 / 磁盘 / 负载 / 温度 / 虚拟化 / BIOS)+ 网络状态 + 服务状态 + IPv6 状态,含实时网速与历史累计流量 |
| 网络状态 / 加速 | 路由表(IPv4/IPv6)、接口地址、nftables flowtable 软加速开关 |
| 页面 | 做什么 |
|---|---|
| 网卡与桥接 | 以 MAC 为主键管理网卡(改名后角色自动跟随),标注备注 / 角色 / 链路 / 速率 / MTU / 驱动;支持多口桥接 |
| WAN 口 | DHCP / 静态 / PPPoE / 其它接入方式,含实时状态与拨号日志 |
| PPPoE 多拨 | 多会话并发拨号、聚合、负载均衡策略 |
| LAN 口 | LAN 网段与地址配置 |
| VLAN / IPTV | 802.1Q VLAN 子接口创建 / 删除,用于光猫 IPTV 单线复用 |
| 网络唤醒 (WOL) | 向局域网内机器发魔术包唤醒 |
| 页面 | 做什么 |
|---|---|
| DHCP 服务 | 地址池、静态绑定、Option 下发;含租约表(在线设备)与「转静态 / 回收」操作 |
| DNS 服务 | 上游 DNS 模式(运营商 / 自定义 / 合并)、自定义规则、静态解析 |
| IPv6 / RA | radvd 前缀 / RDNSS 配置与状态 |
| DHCPv6 / 前缀委派 | DHCPv6 服务端与 PD 获取 |
| 动态域名 DDNS | IPv4 + IPv6 双栈,国内(阿里 / 腾讯 / DNSPod…)与国外服务商 |
| 真·公网 IP 判定 | 判断本机拿到的是不是真公网地址(含 NAT 类型自动检测) |
| 页面 | 做什么 |
|---|---|
| 防火墙 IPv4 | nftables 规则编辑、实时日志滚动查看(带开关) |
| 防火墙 IPv6 | 同上,IPv6 独立规则集 |
| 端口转发 / DMZ | nftables DNAT,简洁稳定的端口映射 |
| UPnP / NAT-PMP | miniupnpd 开关与状态 |
| 访问控制 / 时间组 | Firewalla 风格:按设备 / 时间组 / 应用维度管控(复用 QoS + DPI 链路) |
| 页面 | 做什么 |
|---|---|
| 智能限速 QoS | CAKE / HTB 队列算法、DSCP 优先级(含「视频优先」规则)、按 IP / 端口流控 |
| 应用识别 DPI | nDPI 识别库管理,多前缀代理下载更新 |
| NTP 时间同步 | chrony 上游与状态 |
| 文件共享 SMB/NFS | 跨平台预设模板、权限管理,支持外置设备挂载与格式化 |
| 打印服务 | CUPS 打印服务器 / USB 打印机 RAW 直通(互斥二选一),共享给手机与电脑 |
| AC/AP 管理中心 | OpenSOHO 无线控制器:集中管理 OpenWRT AP 的 Wi-Fi / VLAN / PoE |
| 页面 | 做什么 |
|---|---|
| Web 终端 / 文件 | 浏览器内的 SSH 终端与文件管理器(实时输入输出回显) |
| 通用 API 接口 | 对外通用 REST API,带 OpenAPI 文档与调用范例 |
| 网络诊断工具 | ping / traceroute / mtr / iperf3 / DNS 查询 |
| IPv6 连通性测试 | 分阶段诊断 IPv6 通不通、卡在哪一步 |
| Docker / Compose | 容器 / 镜像 / 网络 / 卷的日常运维 + Compose 项目管理,附 docker run → docker-compose.yml 转换 |
| Docker 引擎配置 | daemon.json 可视化配置:IPv6 一键开启、国内镜像源切换与测速、日志滚动、默认网桥网段 |
| 页面 | 做什么 |
|---|---|
| 系统日志 | journal / syslog 查看与过滤 |
| 连接与流日志 | conntrack 连接表与流量日志(统一日志系统) |
| 页面 | 做什么 |
|---|---|
| 依赖自检与安装 | 43 项依赖逐项探测 + 一键安装(区分必需 / 推荐 / 可选) |
| 磁盘与日志清理 | 回收日志 / 缓存 / 临时文件,可设阈值自动清理 |
| 内核转发与加速 | IP 转发 · 出向伪装 · MSS 钳制 · BBR · SNMP,五项内核开关,每项附说明与联动影响 |
| 证书 / SSL | 自建 CA · 签发服务器证书 · 导入 · 部署给管理后台,附 SSL/TLS 握手体检 |
| 电源控制 | 重启 / 关机 / 定时任务 |
| 用户与密钥 | 系统用户增删改 + SSH 公钥管理(粘贴或上传 .pub) |
| 系统设置 | Web 端口、时区、主机名、审计日志 |
| 主题之家 | Web 主题设计与离线预览,支持 ZIP 导入导出 |
| 升级与保护 | 系统升级与构建保护模式开关 |
| 要求 | |
|---|---|
| CPU | 1 核 x86-64 |
| 内存 | 1 GB |
| 硬盘 | 8 GB |
| 网卡 | 1 个(先做 LAN + 管理口) |
| 系统 | Debian 13 (trixie) |
| 建议 | 说明 | |
|---|---|---|
| CPU | 2 核以上 | 单核也能跑,但开着 PPPoE + QoS + Docker 时会明显吃紧 |
| 内存 | 4 GB | 2 GB 可用,但 Docker 跑起来后余量紧张 |
| 硬盘 | 16 GB SSD | 日志和 Docker 镜像会持续增长,机械盘会让面板变卡 |
| 网卡 | 2 个千兆以上 | WAN + LAN 分开,物理隔离最省心;单口也能用 |
| 网卡芯片 | Intel i210 / i225 / i226 | Linux 驱动成熟,支持多队列与硬件 offload |
| 供电 | 无风扇低功耗平台 (N100 / J4125) | 7×24 跑,功耗和静音比峰值性能重要 |
Drouter 是普通 Debian 软件包,跑在哪都行:
- 物理机:直接装 Debian 13,最推荐 —— 没有虚拟化开销,网卡直通无损耗
- PVE 虚拟机:需要开
net.ipv4.ip_forward之外,还要给 VM 开 混杂模式, 否则桥接的 VLAN 包会被 PVE 丢掉 - 旧笔记本 / 迷你主机:换上 SSD 就是一台安静的路由器
| 网卡数 | 拓扑 | 适用 |
|---|---|---|
| 1 | 单臂路由(LAN = WAN 同接口,靠 VLAN 或子网区分) | 最小可行,配置略绕 |
| 2 | WAN + LAN | 推荐,物理隔离,最直观 |
| 3+ | WAN + LAN + IPTV / DMZ | 有 IPTV 或要隔离 IoT 设备时 |
目标机可以完全断网 —— 没有外网、没有内网源、DNS 都不通,照样一次装完。 这是本项目对「路由器系统」这个使用场景的默认交付形态。
路由器往往出现在不方便接外网的地方:机房、弱电箱、隔离网段、
或者一台你根本不想让它联网的机器。所以 Release 里的
drouter-1.0.5-offline-amd64.tar.gz 不是「只发一个 .deb」,
而是把 Drouter 本体 + 它跑起来需要的全部 Debian 依赖一起打成了一个包。
解包出来是这样:
# 1) 把 tar.gz 拷到目标机(U 盘 / scp / 内网共享都行)
# 2) 解包
tar xzf drouter-1.0.5-offline-amd64.tar.gz
cd drouter-1.0.5-offline-amd64
# 3) 一条命令装完(会自动 sudo)
sudo bash install.sh装完访问 https://<目标机IP>:8443/。全程不碰网络。
它到底自包含到什么程度:
| 依赖包数量 | 236 个 .deb(Drouter 直接依赖 + 全部传递依赖) |
| 覆盖范围 | 从 nftables / dnsmasq / radvd / ppp / chrony 一路递归到最底层 libc6 / zlib1g / dash / diffutils / libc-bin |
| 本地仓库 | 附 debs/Packages + Packages.gz,apt 直接当本地 file: 源用 |
| 完整性校验 | SHA256SUMS,237 条(236 依赖 + 本体) |
| 包体积 | 约 83 MB(tar.gz 压缩后) |
| 系统服务 | 本体 .deb 内含 6 个 systemd 单元,postinst 自动 enable |
包里到底装了什么(点开看)
drouter-1.0.5-offline-amd64/
├── install.sh 安装脚本(自动提权 + 本地 file: 源,零外网)
├── README-离线安装.md 给不熟悉 Linux 的人看的逐步说明
├── SHA256SUMS 237 条校验和(236 依赖 + 本体)
├── drouter_1.0.5_all.deb Drouter 本体(含 6 个 systemd 单元)
└── debs/ 236 个依赖 .deb
├── nftables_*.deb ├─ 直接依赖
├── dnsmasq_*.deb
├── radvd_*.deb
├── ppp_*.deb
├── chrony_*.deb
├── ...
├── libc6_*.deb └─ 最底层传递依赖
├── zlib1g_*.deb
├── dash_*.deb (Essential 包,最容易被漏掉)
├── diffutils_*.deb
├── libc-bin_*.deb
├── Packages 本地仓库索引
└── Packages.gz (同上,gzip 版)
install.sh 做的事情很简单,但每一步都有原因:
- 把
debs/注册成一个临时file:源,然后apt-get install里 所有包名。这样 apt 会自己算依赖顺序。 —— 比dpkg -i debs/*.deb一通乱装可靠得多:dpkg不看顺序, 装到一半就会因为「依赖还没满足」而大面积失败。 - 只挂本地源(
sourceparts指向/dev/null),避免系统里原有的 外网源被读进来、apt 跑去联网找「更新的版本」而卡死。 - 装完报告服务状态和访问地址。
为什么不能只发一个 .deb 让用户自己解决依赖:
.deb 的 Depends 只声明依赖,真正把依赖装上的是 apt。
目标机没外网时 apt 无源可用,用户就得自己凑齐 236 个包 ——
还得算对传递依赖、别漏掉 Essential: yes 的包(它们不会出现在
apt-cache depends --recurse 的输出里)、版本还得跟 trixie 对得上。
这些坑我们已经在打包脚本里踩完了,所以直接帮你打好。
想要更小的包? 如果你的目标机有网(哪怕是内网自建 apt 镜像),
可以只拿 drouter_1.0.5_all.deb(约 445 KB),见下方「方式二」。
已经装过依赖、只想升级本体? 同样只用那个 445 KB 的 .deb
dpkg -i 覆盖安装即可,不必重新走离线包。
如果目标机能连上 Debian 官方源(或内网 apt 镜像),只需要本体那一个文件:
sudo apt install ./drouter_1.0.5_all.deb
sudo drouter-ctl status
apt install ./xxx.deb会自动把Depends交给 apt 去网上补齐 —— 这正是它能「只发一个 445 KB 文件」的前提。 目标机没网时请走方式一,否则 apt 会卡在拉依赖上。
项目提供 drouter-1.0.5-docker.tar(约 169 MB,已含完整根文件系统)。
方式 A:docker compose(推荐)
Release 里附了现成的 docker-compose.yml,直接下下来用:
docker load -i drouter-1.0.5-docker.tar
# 把 docker-compose.yml 放到当前目录
docker compose up -d
docker compose ps # 等 health 变 healthy方式 B:docker run
docker load -i drouter-1.0.5-docker.tar
docker run -d --name drouter --restart unless-stopped \
--network host \
--cap-add NET_ADMIN --cap-add NET_RAW \
-e TZ=Asia/Shanghai \
-v drouter-etc:/etc/drouter \
-v drouter-data:/opt/drouter/data \
-v drouter-snapshots:/opt/drouter/snapshots \
-v drouter-log:/var/log/drouter \
drouter:1.0.5两种方式加载后镜像标签都是 drouter:1.0.5(另有一个
liuzhuohua/drouter:1.0.5 别名,同一个镜像)。
访问 https://<宿主IP>:8443/,账号 admin / admin123。
关于参数,实测结论如下:
| 参数 | 必要性 | 说明 |
|---|---|---|
--network host |
必需 | 容器要直接读写宿主的网络接口和 nftables 规则,bridge 模式下看不到真实网卡 |
--cap-add NET_ADMIN |
必需 | 否则 nft 操作报 Operation not permitted,防火墙页会失效 |
--cap-add NET_RAW |
建议 | 部分探测类功能(ping / traceroute)需要 |
| 四个命名卷 | 建议 | 配置、数据、快照、日志。不挂出来容器重建就全丢 |
不需要
--privileged。网上很多教程图省事都写它,但 Drouter 只需要NET_ADMIN+NET_RAW。给privileged等于把宿主机完全敞开 —— 除非在排查权限问题,否则用最小权限就好。
端口由配置文件决定,不是环境变量。
network_mode: host下ports:会被 Docker 忽略。端口存在/etc/drouter/web-port,默认 8443, 要改请去界面改(DROUTER_WEB_PORT环境变量只在首次启动播种,之后会失效, 这是故意的 —— 见packaging/docker/packaging/docker/DOCKER-GUIDE.md)。
Docker 形态只建议用来体验界面和 API。容器里没有 systemd, 所以「服务管理」页会显示
active: unknown(这是预期的优雅降级,不是故障); 真正当路由器用请走 deb 安装。
git clone https://github.com/liuzhuohua/drouter.git
cd drouter
# 本体 deb(→ dist/drouter_1.0.5_all.deb,约 445 KB)
bash packaging/build-deb.sh 1.0.5
# 离线依赖库(→ dist/offline-deps/,236 个 .deb + Packages 索引)
bash scripts/make-offline-deps.sh
# 自包含离线包(→ dist/drouter-1.0.5-offline-amd64.tar.gz,约 83 MB)
bash packaging/build-offline-bundle.sh 1.0.5
# Docker 镜像(→ dist/drouter-1.0.5-docker.tar,约 169 MB)
bash packaging/build-docker.sh 1.0.5构建顺序上,build-offline-bundle.sh 会自己先调 build-deb.sh
和 make-offline-deps.sh,所以想一步到位只跑它就行。
构建环境要求:Debian 13 (trixie) / amd64。 依赖闭包是在空 dpkg status 的临时 apt 根里求解的(而不是用当前机器的 已装状态),否则「开发机上恰好装过」的包会被 apt 判为"已满足"而漏收 —— 到了干净目标机上就变成
Depends: xxx but it is not installable。 这个坑在make-offline-deps.sh里有详细注释。
装好之后的第一小时,建议按这个顺序来:
浏览器访问 https://<路由器IP>:8443/
⚠️ 用的是自签证书,浏览器会报「不安全」。这是正常的 —— 点「高级」→「继续访问」。 想要不报警,去证书 / SSL 页面签发一张自己的证书并部署。
默认账号:admin / admin123
第一件事就是改掉它(系统设置 → 改密码)。
左侧菜单第一项就是新手向导。它会带你确认四件事:
- 外网通不通(有默认路由 + 能 ping 通国内地址)
- 内网在不在发地址(DHCP 开着吗?地址池有没有把自己圈进去?)
- DNS 能不能解析
- IPv6 需不需要开
每一步都会给出独立的成败结论,而不是一个笼统的总分 —— 因为新手真正需要知道的是"哪一步还没做",不是"你得了 60 分"。
进网卡与桥接,给每张网卡标注:
- 备注:这是哪个口(电信光猫 / 客厅交换机 / 书房墙插)
- 角色:WAN / LAN / 未分配
角色是按 MAC 地址记的。以后网卡改名(
ens18→enp1s0)角色不会丢。
进 WAN 口,选你的接入方式:
- PPPoE:填宽带账号密码(运营商光猫桥接时用这个)
- DHCP:光猫已经拨号,路由器拿地址即可
- 静态:有固定 IP 的专线
点保存 → 点应用 → 看拨号日志确认连上。
到这一步为止,Drouter 都还只是个"旁观者"。要让它接管,需要:
- 确认 WAN 口 通了、LAN 口 配好了
- 进内核转发与加速,开启 IP 转发 和 出向伪装
- 关掉原路由器的 DHCP,或把 Drouter 的 LAN 口接到交换机上
- 把客户端的网关指向 Drouter
⚠️ 第 3、4 步会切断现有网络。建议留一个能进物理控制台的方式(显示器 + 键盘, 或者确保 RealVNC 会话可用),万一配错了还能救回来。
| 事项 | 说明 |
|---|---|
| 不要在唯一出口上直接试 | 第一次装建议装在一台没在承担路由的机器上,配好了再切 |
| RealVNC 用户注意 | 本项目所有动作都避开了 5900 端口,也不会动 X 会话 / LightDM。如果你跑着 VNC,它不会受影响 |
| 端口冲突 | 装完不会自动启动 dnsmasq / radvd / kea。但如果这些服务本来就在跑,请先停掉再让 Drouter 接管 |
| PVE 虚拟机 | 需要给 VM 网卡开混杂模式,否则桥接 / VLAN 的包会被宿主丢掉 |
| 系统时间 | 面板和证书校验都依赖正确时间。裸装 Debian 若时间不对,先 sudo timedatectl set-ntp true |
| 离线安装前 | 确认目标机是 amd64、剩余磁盘 ≥ 1.5 GB。离线包里的依赖是按 Debian 13 (trixie) 下载的,装到别的版本上可能出现版本不匹配 |
这一节单独说,因为它是本项目默认推荐的交付方式。
能保证什么
- 目标机无外网、无内网源、DNS 不可达也能完整装好 —— 全部 236 个依赖
已随包提供,
install.sh走的是本地file:源,不发起任何网络请求。 - 安装过程不需要目标机上有
apt之外的工具(install.sh只用 POSIX shell +df/cut,连awk都不依赖 —— 它不一定在最小系统里)。 - 包内
SHA256SUMS可离线校验完整性:sha256sum -c SHA256SUMS
必须知道的约束
| 约束 | 原因 |
|---|---|
| 架构必须匹配 | 包名带 -amd64,里面是 x86_64 的二进制。arm64 目标机请按文档自行重建 |
| 发行版必须匹配 | 依赖来自 trixie 仓库。跨版本(如 bookworm)会出现 libc6 版本冲突 |
| 磁盘 ≥ 1.5 GB | 236 个 deb 解包 + 安装要占几百 MB;install.sh 会在低于 1.5 GB 时告警 |
| 装完要手动改密码 | 默认 admin / admin123,离线环境下尤其要第一时间改 |
装完不会发生什么(这点很重要)
install.sh 只安装软件,不会:
- ❌ 启动
dnsmasq/radvd/kea等会发 DHCP 的服务 - ❌ 修改默认路由或打开 IP 转发
- ❌ 改动任何现有网络配置
装完之后这台机器仍然是一台普通主机,直到你打开面板、亲手点「应用」。 这是整个项目的核心设计原则,离线安装同样遵守。
- 保存 ≠ 应用。改了配置只点「保存」,重启后不会生效。要生效必须点「应用」。
- 默认只写盘不生效。「应用」时会先渲染预览,确认没问题再下发。
- 快照会占空间。自动快照默认保留最近若干份,硬盘小时去磁盘与日志清理里调阈值。
- 构建保护模式。如果
/etc/drouter/BUILD_MODE存在,所有改网络的动作会被拒绝。 这是给"在正在使用的机器上装机"准备的,配好后去升级与保护页面解除。 - Web 端口改动要重启面板。改完
8443后记得用新端口访问;改错了可以用sudo drouter-ctl webport 8443从命令行改回来。 - API 接口无鉴权时不要暴露。通用 API 接口页面默认只监听本机, 如果要对内网开放,请自行在防火墙里加来源限制。
| 项目 | 支持情况 |
|---|---|
| Debian 13 (trixie) | ✅ 主要目标,全功能验证 |
| Debian 12 (bookworm) | ⚠️ 可用,但 docker-compose 包名不同,nftables 版本较老 |
| Ubuntu 24.04 | ⚠️ 大体可用,docker-compose-v2 是 Ubuntu 的叫法 |
| Debian 11 及更早 | ❌ 不支持(Python 版本与 nftables 语法不兼容) |
| 架构 | amd64 已充分验证;arm64 理论可用(Architecture: all,依赖需自行确认) |
drouter/
├── backend/ Python 3 后端(标准库,无第三方依赖)
│ ├── drouter-web.py HTTP/HTTPS 服务、路由层、静态文件与 gzip 缓存
│ ├── drouter-helper.py 业务逻辑主体:动作分发、43 个功能实现、渲染调用
│ ├── drouter-helpd.py 常驻执行守护(避免每次请求 fork 一个 helper)
│ ├── render.py 配置渲染器:settings → 原生配置文件
│ ├── theme.py 主题之日:主题解析、离线预览、导入导出
│ ├── drouter-logd.py 统一日志采集
│ ├── drouter-snapshotd.py 自动快照
│ ├── drouter-rescue.py 紧急救援通道
│ └── drouter-shelld.py Web 终端的 shell 会话
├── web/ 前端(原生,无构建)
│ ├── index.html 入口页
│ ├── app.js 单文件 SPA:43 个视图 + 路由 + 状态管理
│ ├── app.css 样式
│ └── logo.svg 标识
├── _dev/ 测试与探测
│ ├── t-*.py 40 套单元测试(预检链里全跑)
│ ├── live-*.py 真机验收脚本(需在目标机上执行)
│ └── *.js 前端契约测试
├── devtools/ 开发工具
│ ├── sync.sh 一键部署:预检 → 打包 → 上传 → 部署
│ ├── shots-map.py 截图入库:中文名 → ASCII 名映射与复制
│ ├── check-shots.py 截图覆盖度:功能页 ↔ 截图 ↔ README 三方对账
│ ├── check-md-links.py 文档本地引用死链检查
│ ├── check-views.js 菜单 ↔ 视图映射检查
│ ├── check-render.js 35+ 视图离线渲染检查
│ └── check-mobile.js 手机适配检查
├── scripts/ 运维脚本
│ ├── deploy.sh 部署脚本(被 sync.sh 调用)
│ ├── drouter-ctl.sh 命令行管理工具
│ ├── make-offline-deps.sh 离线依赖打包
│ └── install-base.sh 底座安装
├── packaging/ 打包
│ ├── build-deb.sh deb 构建
│ ├── build-docker.sh Docker 镜像构建
│ ├── deb/ control / postinst / prerm / postrm
│ └── docker/ Dockerfile / docker-init.sh
└── docs/ 文档
├── *.md 规格 / 部署 / 测试等中文文档
└── screenshots/ 78 张真实界面截图(jpg)
浏览器
│ HTTPS (8443)
▼
drouter-web.py ThreadingHTTPServer,单进程多线程
│ Unix socket IPC
▼
drouter-helpd.py 常驻守护(socketserver.ThreadingUnixStreamServer)
│ run_action() 无全局锁,可并发
▼
drouter-helper.py 75 个 ACTIONS 动作
│
├─ render.py 渲染原生配置
└─ 系统调用 nft / systemctl / pppd / dnsmasq ...
关键设计:
- 常驻守护:Web 层先试
helpd快路径,失败才回退 fork 一个新 helper。 否则每个 API 请求都要 fork 一个 1.6 万行的 Python —— 在 2 核机器上不可接受。 - 无全局锁:
run_action()不加锁,多个请求可以并发执行(读操作占绝大多数)。 - 零 fork 读接口:
read_sysinfo/read_metrics这类"每次切页面都调"的接口, 全部直读/proc与os.statvfs(),不 forkdf/hostname/uname。 - 批量取服务状态:
read_services用一次systemctl show取回 18 个单元的状态, 而不是 18 × 2 = 36 次systemctl is-active/is-enabled。
这一节解释几个看起来奇怪但故意这么做的决定。
因为最容易出事的场景是:在一台正在提供服务的机器上装路由系统, 装完发现 DHCP 服务端起来了,整个局域网开始抢地址。
所以所有"抢端口"的行为都需要用户显式触发。这不是偷懒,是设计。
因为 apt 默认会装 Recommends,而 smartmontools 装完会自动拉起 smartd 常驻。
对一台路由器来说这是个意料之外的常驻服务。
同理,samba / nfs-kernel-server / docker.io 也都降级到 Suggests ——
它们装完会启用文件共享服务和 Docker 守护,在 4GB 机器上很重。
用户需要时在依赖自检与安装页面上逐项装。
因为 control 是 deb822 格式,不保证支持 # 注释行。
某些 dpkg 工具遇到注释会解析失败。所以所有说明都写在 build-deb.sh 里。
它是 QoS 智能限速创建的 IFB 虚拟网卡。
Linux 的流量整形(tc)只能管出向流量。要限速入向流量,得先把入向包 重定向到一块 IFB 设备上,再在那上面做整形。
所以看到 ifb-drouter 时不用担心 —— 它不是紧急通道,也不用给它指派角色。
单文件 SPA + 原生 JS,11200 行,没有构建步骤。
因为目标是"改完刷新就能看到",而不是"改完等 30 秒 webpack"。 对于这个规模的面板,框架带来的收益(组件复用、状态管理) 抵不过构建链带来的复杂度。
代价是:定时器清理、事件解绑、DOM 判空这些事得自己记住。 项目里用 40 套单测 + 3 个前端检查脚本(菜单映射 / 离线渲染 / 手机适配)守住这些点。
装完打不开 8443 端口?
sudo drouter-ctl status # 看服务状态
sudo journalctl -u drouter-web -n 50 # 看报错
sudo ss -tlnp | grep 8443 # 看端口有没有在听常见原因:
- 服务没起来 —— 看
journalctl报什么 - 防火墙挡了 —— 检查
nft list ruleset有没有放行 8443 - 浏览器拒绝自签证书 —— 换 Firefox 或手动点「继续访问」
改错了配置,网络不通了怎么办?
按严重程度依次尝试:
- 回滚快照 —— 有本地控制台的话,
sudo drouter-ctl rollback - 救援通道 ——
sudo systemctl start drouter-rescue,它会起一个最小可用的网络配置 - 物理控制台 —— 接显示器和键盘,直接改
/etc/network/interfaces或nmcli
这也是为什么装之前一定要留一个备用进系统的方式。
为什么我的 `<某个包>` 装不上?
大概率是包名在你那个发行版上不一样。这个项目主要在 Debian 13 上测。
最典型的例子:
| 功能 | Debian 13 | Ubuntu |
|---|---|---|
| Compose v2 | docker-compose |
docker-compose-v2 |
去依赖自检与安装页面看它探测的是哪个包名,然后对照你系统的实际包名。
💡 一个已实测的 apt 行为:
apt-get install a b c里只要有一个包名查不到, 整体就会中止,同命令里的其它包一个都不装。所以批量安装失败时, 先单独apt-cache policy <包名>确认每个包都存在。
能当旁路由用吗?
能。这正是它的设计场景之一 —— 先作为旁路由跑起来(不接管主路由的 DHCP), 把 QoS、DPI、DDNS、Docker 这些"附加能力"先接上, 等你觉得稳了,再决定要不要把它提到主路由位置。
怎么升级?
# 下载新版 deb
sudo apt install ./drouter_1.0.5_all.deb # 直接覆盖安装,配置保留配置在 /etc/drouter/ 和 SQLite 里,apt remove 也会保留(purge 才删)。
怎么完全卸载?
sudo apt remove drouter # 删程序,保留配置
sudo apt purge drouter # 连配置一起删注意:已经应用过的原生配置(/etc/nftables.conf、/etc/dnsmasq.conf 等)
不会自动还原 —— 它们是系统配置,不是软件包的一部分。
要还原请用快照回滚,或手动改。
纯修复与加固版本,无新增功能,不改动配置存储格式(老配置直接可用)。 1.0.4 清完「假输入框」之后,这一轮把前后端再过一遍,主题是三类: 能被利用的安全缺陷、会慢慢吃掉资源的生命周期问题、以及低配置机器上的性能水位。
- 安全:改密码可以顺手拿到 root。
chpasswd是按行读的,用户名或密码里 塞一个换行,第二行就会被当成另一条记录执行 —— 等于直接改 root 密码。 现在用户名/密码一律拒绝换行、回车与控制字符。同类还修了:删除用户从 「写死保护 root/ajeef」改成「保护全部 UID<1000 系统账号」; WOL 唤醒的接口名/目标地址加白名单(原先拼进sh -c); ACL 的 hosts 字段改用ipaddress严格校验(原先':' in h这种弱判断 能漏进 nftables 规则);存储挂载点限定在/mnt|/media|/srv之下 (原先target=/etc会把 U 盘盖到 /etc 上,系统立刻不可用)。 - 安全:文件管理器的目录穿越收口。 拒绝清单从「文件级」扩到「目录级」
(
.ssh、/etc/sudoers.d、/etc/pam.d等),再加一道按文件名的拦截 (authorized_keys、shadow、sudoers…)—— 原先..绕一层就能 写到 root 的 SSH 密钥,等于开后门。 - 安全:前端 201 处未转义的
value="${...}"全部补esc(),href一律过httpUrl()只放行 http/https(防javascript:伪协议), 主题导出的注释同时剥掉/*与*/(1.0.4 只剥了一半,照样能闭合注入)。 - 丢数据:三个页面切走再回来,未保存的改动被静默冲掉。 访问控制 / 文件共享 / DDNS 进入页面时都会无条件用服务端数据覆盖草稿。 现在页内任何改动都会登记「脏页」,再进页面时保留你的编辑; 保存成功才清除。这是全站唯一真正不可逆的丢数据路径。
- 假功能:LAN 页的「网关地址 / 域名后缀」改了等于没改。
这两个值实际由 dnsmasq 下发,页面却写进了谁也不会读的
system模块死键。 现在与 DHCP 页 Option 3 同源。另外 UPnP 的「刷新映射表」按钮原先会 顺手把服务启动然后给你看一句静态提示 —— 现在走真正的只读接口read:upnpmap,查询绝不再产生副作用。 - 资源:PTY 终端三条命。 缓冲区不再无上限(8MB 封顶,超出丢最旧)、 会话数用信号量真正卡住(原先是「先查再用」的竞态)、空闲会话有后台 线程定期回收(原先只在「满了」那一刻才顺手清)。离开终端页面时 前端也会主动断开会话,不再白占 30 分钟。
- 资源:Web 服务并发与内存水位。 工作线程 48 封顶(原先
daemon_threads只是「退出不等待」,并不是限流)、请求体 16MB 封顶、会话表 500 封顶且 过期判断改用单调时钟(原先系统时间一回调,会话集体「永生」或集体过期)、 审计表 2 万行封顶自动裁剪、登录失败计数表封顶。 - 资源:日志与快照不再能撑爆磁盘。 helper 自身日志 32MB 封顶自动轮转; 快照前检查剩余空间(<1GB 直接跳过并说明);文件下载封顶从 512MB 收到 20MB —— 512MB 这个数字本来就超过了下载通道 32MB 的单条响应上限, 大文件只会静默失败,回退路径还会把 ~700MB 输出整个读进内存。
- 性能:
/api/config从 16 次开关 SQLite 改成 1 次;磁盘清理状态页的 递归扫描有 30 秒缓存(原先每进一次页面就全量os.walk一遍 /var/log); gzip 缓存按字节数设闸(24MB);标签页在后台时心跳暂停、终端轮询降频。 - 加固:全部 11 处「断电就剩半截」的配置写入改原子写(临时文件 +
os.replace);rescue 与 snapshot 两个 systemd 单元补上MemoryMax内存闸(连同 helper 重建单元的那处模板,三处同步)。 - 修:DHCPv6「停用」不停用。
enabled=false时 dhcpcd 配置里仍然输出 实际配置行,现在停用就只留注释。另修租约回收改用dhcp_release(已登记进依赖清单,未安装时自动退化为删租约文件 + 重载并如实告知)、 VLAN 只删自己创建的接口(原先按名字匹配,可能删掉用户手建的)、 探测公网前清掉过期结果文件(原先一次探测成功就永久显示「外网可达」)。
纯修复版本,无新增功能,不改动配置存储格式(老配置直接可用)。 这一轮是把全量代码(约 4.5 万行)从头过了一遍,重点找两类最伤人的问题:
- 「假输入框」 —— 页面上有这个框、能填、能保存,后端却从来不读,等于白填;
- 「隐身字段」 —— 后端真的会用,页面上却没有入口,永远走默认值。
排查方式是拿 AST 把渲染器里所有读取的配置键抽出来,再和页面上的输入框清单做差集。
- 修:点了「迁移到 systemd-networkd」,写出来的文件名叫
name、内容写着content。 渲染层约定是所有渲染器都返回「(绝对路径, 内容)」二元组列表,唯独 networkd 这个 返回的是字典。调用方按二元组去解包,字典的两个键刚好被当成路径和内容 —— 迁移不是「失败」,而是真的生成了一堆垃圾文件。这是本轮唯一会直接写坏系统的缺陷。 - 修:DMZ 规则方向写反。 注释写的是「排除到本机自身的流量」,条件却写成了它的 反面:本来只有外部流量该被转进内网主机,实际连管理流量也一并转走。
- 修:一批「填了等于没填」的输入框(5 处)。 ① WAN 页的 MTU 与「是否接受
上游 DNS」后端从不读,现在真正写进
systemd-networkd的MTUBytes=/UseDNS=; ② DHCPv6 页的「子网 ID」绑的是个不存在的键,真正生效的前缀委派 ID 无入口, 现在绑对了;③ Samba 的「WINS 支持」要求另一个从不回填的字段同时为真,勾了也 永不生效;④ 网桥的「启用 STP」没有绑定事件,勾完保存不进去;⑤ 主题设计器里 「按主色生成整套配色」按钮压根没接线,点了没反应。 - 修:IPv6 路由通告页缺少「下发 DNS / 搜索域」的生命期输入框。 1.0.3 修了字段 错位,但页面上一直没有入口 —— 现在补齐。
- 修:迁移预览永远报「WAN 网卡不能为空」。 前端只提交了 LAN 段,WAN 和网桥配置 一次都没发过,预览里既看不到 WAN 也看不到网桥。
- 修:一批校验缺失导致的「保存完服务起不来 / 页面 500」。 过去这些字段是直接从
表单拼进配置文件的:dnsmasq 的域名与日志文件路径、miniupnpd 的租约文件路径与
UUID、PPPoE 的运营商名与服务名、IPv6 前缀委派 ID、路由通告的地址池五项、
NFS 的导出选项与线程数 —— 现在全部按各自语法校验并给中文提示。另外
chrony 的服务器地址校验只认域名和 IPv4,填 IPv6 的 NTP 服务器会被误判成非法。
顺带修了
int()前只判断isdigit()的老毛病:Unicode 的上标数字能通过isdigit()却会让int()抛异常,界面直接 500。 - 修:自签证书的 SAN 里写死了开发者的内网 IP。 生成的证书主题别名里必定带上
192.168.7.3,跟你的机器一点关系都没有;有些客户端会因为它校验不过而报警。 现在改为从本机实际地址和默认路由推导,并保底保留127.0.0.1/localhost。 同时补了 openssl 失败检测 —— 过去生成失败时不会报错,只是给你一个不存在的证书路径。 - 修:两处模板注入。 ① DDNS 面板的「记录名 / 服务商」是拼进 HTML 的,
填一段带尖括号的内容就能在页面上执行自己的脚本;② 导出的主题 CSS 把主题名和版本
拼进注释里,名字里带
*/就能提前闭合注释,往里塞任意 CSS。现在前端转义、 后端清注释结束符,两边都堵住。
纯修复版本,无新增功能,不改动配置存储格式(老配置直接可用)。
- 修:IPv6 路由通告里填了 IPv4 DNS,就会生成一份 radvd 起不来的配置。
RDNSS字段原先完全不校验(同一段代码里prefix和DNSSL都校验了,唯独漏了它)。 在「下发 DNS」框里顺手填223.5.5.5(最顺手的写法)会原样写进radvd.conf, radvd 直接syntax error起不来;界面上只回一句英文,完全指不到是哪个字段。 现在逐项按 IPv6 地址校验并给出中文提示,且多值支持逗号/空格两种写法 (统一按空格输出 —— 逗号形式 radvd 本来就不认)。顺带修了「DNSSL 生命期」 实际读的是 RDNSS 生命期这个张冠李戴。 - 修:自动清理的「每天 00:00」存不下来,实际跑在 04:00。
前端
Number(v) || 4与后端int(cfg.get('hour') or 4)都把 0 当成「没填」。 另外执行时刻的判定从「正好等于」改成「不早于」:机器在计划时刻恰好在关机/重启时, 当天会补做,而不是整天跳过、要等到第二天。 - 修:重新部署会静默回退用户设置(3 处)。 这是最烦人的一类问题 ——
用户只会觉得「部署完我的设置莫名其妙变回去了」。
① 生效主题被无条件写回
default,自定义主题每次部署都被打回; ②isp-dns.conf被无条件覆盖,pppd 已经拿到的运营商 DNS 被擦掉,上游解析变空 直到下次拨号;③ 自动清理被无条件enabled=true,用户在界面上明确关掉的 「自动删文件」策略会被重新打开(清理是本项目唯一真删文件的模块,这条最不该发生)。 现在三者都改成「只在不存在时初始化」,并复用容器版docker-init.sh已有的写法。 - 修:浏览器切页/关标签会在 journal 里刷一整段 Python traceback。
BrokenPipeError/ConnectionResetError属于「对面先挂了」,不是服务端的错, 却足以把 journal 刷满、淹掉真正的报错(实测 3 天攒了几十条)。现在只吞这几类。 - 修:
/etc、/opt、/var/log里残留的名字带\r的脏条目。 早先 CRLF 的部署脚本在 Linux 上执行时,行尾的\r粘进了参数,真的建出了dnsmasq.d\r、nftables.d\r、active-theme\r、/opt/drouter\r这类条目 ——ls会出现「同名条目两遍」的重影,配置快照也会反复把它们打包进去。 新增devtools/fix-crlf-names.py(默认只预演,加--apply才删;只删存在同名 正常兄弟的条目,目录里若有兄弟没有的文件就拒绝删),并把「文件名不得含控制字符」 加进发布前预检。
纯修复版本,无新增功能,不改动配置存储格式(老配置直接可用)。
- 修:DHCP 页会把
option 3/option 6渲染成重复指令。 页面上有专属字段 (Option code 3 · 网关/Option code 6 · DNS)和「自定义 Options」表两处 能写同一个 code,两处都填就会各输出一遍 —— 而 dnsmasq 对 3/6 这类列表型 option 是追加语义,于是客户端收到重复的网关、以及顺序被搅乱的 DNS 列表 (公网 DNS 排在前面,本机 dnsmasq 等于形同虚设)。 现在按 code 合并成一行并顺序去重;标了「强制」的 3/6 行语义不同,仍单独输出。 新建配置也不再预置与专属字段重复的 code 3/6 行。 - 改:
code 6的填写提示。 原占位符是223.5.5.5,119.29.29.29,容易让人把 上游 DNS 填进下发给客户端的 option 6。现改为提示填本机地址 (客户端查本机、本机再转发到上游)。 - 修:dnsmasq 预检失败时给出可读诊断。 原先把子进程的英文原文直接抛给用户,
看不出问题出在哪。例如
failed to seed the random number generator其实与配置无关 —— 是宿主机的/dev/urandom设备节点不存在(/dev曾被清空), 现在会明确指向系统层面的原因与补救方向。
随包附 devtools/fix-dev-nodes.sh:幂等地补齐缺失的 /dev 设备节点,
设备号取自内核 devices.txt、/proc/partitions 与 sysfs,不硬编码。
纯修复版本,无新增功能,不改动任何配置格式。
- 修:Web SSH 终端任何账号都连不上(
out of pty devices)。 真因不是伪终端耗尽(kernel.pty.nr为 0),而是/dev/ptmx这个符号链接丢失。 现在守护进程启动时与每次创建失败时都会自愈(补链接 →mknod兜底), 并给出可照抄的修复提示,不再只抛一句误导性的系统报错。 - 修:终端并发满员后整个服务被冻死。 会话锁不可重入,而「满员 → 回收空闲会话」
会在持锁状态下二次取同一把锁,同线程永久阻塞且不报错、不写日志。
改为可重入锁 + 回收动作移出锁外。实测第 9 个连接 0.01 秒返回
BUSY, 8 个会话 0.87 秒全部清理、残留 0,无 fd 泄漏。 - 改:终端外观。 隐藏右侧滚动条(保留滚动能力)、高度随视口自适应并跟随最新输出、 新增「清屏」与「↓ 最新」按钮。
- 修:页脚协议标注错误。 原先写「GNU GPL v3」,与仓库实际的 MIT
LICENSE不符。
43 个功能页面、9 个纯标准库后端模块、6 个 systemd 单元、自包含离线安装包 (本体 + 236 个依赖)、Docker 镜像与 compose 编排。
欢迎 Issue 和 PR。
git clone https://github.com/liuzhuohua/drouter.git
cd drouter
# 本地跑测试(不需要目标机)
python3 _dev/t-*.py # 40 套单元测试
node devtools/check-views.js # 菜单映射检查
node devtools/check-render.js # 视图渲染检查
node devtools/check-mobile.js # 手机适配检查- 全部单测通过(40 套)
- 前端三查通过(check-views / check-render / check-mobile)
- 文件是 LF 换行(用 Windows 编辑容易写成 CRLF,Linux 上会执行失败)
- 新增功能请同时加测试 —— 这个项目的复杂度已经到了"不能靠肉眼保证"的程度
bash devtools/sync.sh这条命令会依次做:跑全部预检 → 打包 → 上传 → 部署。预检不过就不会上传。
- 后端:Python 3 标准库,不用第三方包
- 前端:原生 JS,
function viewXxx()必须是函数声明(因为const VIEWS在模块顶层求值,靠的是变量提升) - 注释:解释为什么这么做,而不是做了什么。特别是那些"看起来可以简化但其实是踩过坑"的地方
Drouter · 让 Debian 成为一台你可以完全掌控的路由器
MIT License · 作者 火麒麟 (ajeef)













































































