极空间部署 Dashlet:Docker 搭建私人导航仪表盘,再配置固定公网访问
前言
NAS 上装的软件越来越多,我发现最麻烦的往往不是启动服务,而是下次想用时又得翻收藏夹:一个管理页面用 IP 加端口,另一个是局域网域名,常用网站还散落在浏览器书签里。把这些入口放进同一个页面,比反复记地址省事得多。但我也不想为了一个导航首页再搭一套庞大的监控系统,日常真正需要的可能只是清楚的图标、容易查找的服务列表,以及在电脑和手机上都能打开的界面。Dashlet 的思路就很贴近这个需求:通过配置文件组织服务,提供主题、背景、排序和拖拽调整,让私人首页由自己维护。
这次用极空间作为部署设备,先通过 SSH 查看 Docker 环境,再用 ghcr.io/jaberio/dashlet:latest 运行 Dashlet,保留 Docker 命令和 Compose 两种方式,并解释 8989:8989 与 ./data:/app/public 分别负责什么。页面打开后,我会导入一份包含 GitHub、YouTube、Google 等 12 个示例入口的 config.json,再看看哪些设置真正影响日常使用。最后通过 cpolar 为本地 8989 创建随机公网地址,再绑定固定二级子域名 dashlet。整个过程会把"导航页面""具体服务"和"公网入口"分开:能从外面打开 Dashlet,不代表页面列出的每个内网服务都已经能从外面直接访问。

1. 为什么是 Dashlet,而不是再建一套监控平台
Dashlet 的实际定位更接近一张可定制的服务导航页:把常用网址集中到一个界面,用名称、图标、描述和排序让入口更容易辨认。它采用原生 JavaScript 与 SCSS,界面带有玻璃磨砂效果,并提供深浅主题、系统自动主题、自定义背景、搜索入口和拖拽排序。
对我而言,它解决的是"服务入口在哪里"这个问题,而不是替代 Prometheus、Grafana 之类的指标采集与分析工具。配置里的 services 是网址列表;只有接入了真实的数据来源或额外功能,才能谈具体的服务器状态、网络流量或日志数据。单凭把链接放进首页,不会自动生成监控指标。
这一点也决定了使用顺序:先让 Dashlet 在极空间运行,再导入服务配置,确认每个链接指向正确位置,最后考虑要不要从外网打开整个导航页。
2. 先确认极空间的 SSH 和 Docker 环境
在极空间中开启 SSH 服务,使用 Windows PowerShell 或 Mac 终端登录。这里的 IP 替换为自己的极空间局域网地址:
shell
ssh root@IP

进入终端后检查 Docker:
shell
docker -v
systemctl status -v

docker -v 可以查看 Docker 命令的版本;systemctl status -v 没有指定服务名,不能仅凭它的输出就断定 Docker 守护进程是否正常。实际部署前还应结合极空间的 Docker 管理界面确认服务状态。这样后面如果容器启动失败,就能先排除基础环境问题,而不是反复修改 Dashlet 配置。
3. Docker 部署:先弄清端口和目录
创建 Dashlet 目录:
shell
mkdir Dashlet

注意,这条命令只负责创建 Dashlet 文件夹,没有自动切换工作目录。下面的目录挂载使用相对路径,执行前应确认自己所在的位置,避免把配置文件保存到预期之外的宿主机目录。
直接运行容器可以使用:
shell
docker run -d \
--name dashlet \
--restart unless-stopped \
-p 8989:8989 \
-v $(pwd)/data:/app/public \
ghcr.io/jaberio/dashlet:latest
如果习惯用 Compose 维护容器,也可以采用下面的配置;本次演示使用 Compose:
shell
services:
dashlet:
image: ghcr.io/jaberio/dashlet:latest
container_name: dashlet
restart: unless-stopped
ports:
- "8989:8989"
volumes:
- ./data:/app/public

两种方式使用相同镜像 ghcr.io/jaberio/dashlet:latest、容器名 dashlet 和重启策略 unless-stopped。其中 8989:8989 将极空间的 8989 映射到容器同名端口;./data:/app/public 或 $(pwd)/data:/app/public 则把宿主机数据目录挂载到容器的公开文件目录。因为配置文件与这个挂载目录有关,后续维护时要留意实际文件是否存在、目录是否指向正确位置;如果页面空白,也应检查挂载内容,而不是只看容器状态。
容器运行后,在浏览器访问 http://极空间IP:8989:

页面能打开,说明本地 Web 入口已经可用。下一步才是让它显示自己真正需要的服务。
4. 导入 config.json,让首页从空壳变成网址清单
进入设置界面,找到导入功能:


选择需要导入的配置文件:

编辑后,点击导入配置文件:
下面是一份可参考的完整配置。它保留了 settings 与 services 两个主要部分,示例共包含 12 个常用网站。实际编辑时,服务名称、网址和图标可以换成自己的 NAS 应用或其他常用入口。
shell
{
"settings": {
"theme": "system",
"appTitle": "Dashlet",
"greeting": "Welcome",
"accentColor": "#3b82f6",
"blur": true,
"animations": true,
"openNewTab": true,
"layout": "list",
"wallpaper": "",
"searchProvider": "https://duckduckgo.com/?q=",
"customCSS": "",
"disableDragDrop": false,
"dragDelay": 0,
"searchEnabled": true,
"footerText": "Powered by",
"footerColor": "",
"sortBy": "manual"
},
"services": [
{
"id": "1",
"name": "GitHub",
"description": "Code hosting",
"url": "https://github.com",
"icon": "https://github.githubassets.com/favicons/favicon.png"
},
{
"id": "2",
"name": "YouTube",
"description": "Watch videos",
"url": "https://youtube.com",
"icon": "https://www.youtube.com/s/desktop/10c3d9b4/img/favicon_144x144.png"
},
{
"id": "3",
"name": "Google",
"description": "Search engine",
"url": "https://www.google.com",
"icon": "https://www.google.com/favicon.ico"
},
{
"id": "4",
"name": "Gmail",
"description": "Email service",
"url": "https://mail.google.com",
"icon": "https://ssl.gstatic.com/ui/v1/icons/mail/rfr/gmail.ico"
},
{
"id": "5",
"name": "Notion",
"description": "All-in-one workspace",
"url": "https://notion.so",
"icon": "https://www.notion.so/images/favicon.ico"
},
{
"id": "6",
"name": "Reddit",
"description": "Social news & discussion",
"url": "https://reddit.com",
"icon": "https://www.redditstatic.com/desktop2x/img/favicon/favicon-32x32.png"
},
{
"id": "7",
"name": "Twitter / X",
"description": "Social media",
"url": "https://twitter.com",
"icon": "https://abs.twimg.com/favicons/twitter.3.ico"
},
{
"id": "8",
"name": "Stack Overflow",
"description": "Developer Q&A",
"url": "https://stackoverflow.com",
"icon": "https://cdn.sstatic.net/Sites/stackoverflow/Img/favicon.ico"
},
{
"id": "9",
"name": "Wikipedia",
"description": "Free encyclopedia",
"url": "https://en.wikipedia.org",
"icon": "https://en.wikipedia.org/static/favicon/wikipedia.ico"
},
{
"id": "10",
"name": "Netflix",
"description": "Streaming movies & shows",
"url": "https://netflix.com",
"icon": "https://assets.nflxext.com/us/ffe/siteui/common/icons/nficon2016.ico"
},
{
"id": "11",
"name": "Spotify",
"description": "Music streaming",
"url": "https://open.spotify.com",
"icon": "https://open.scdn.co/cdn/images/favicon32.c6a9e59d8375a83e22c7b79e9b7a3e3d.png"
},
{
"id": "12",
"name": "Weather",
"description": "Check local forecast",
"url": "https://weather.com",
"icon": "https://weather.com/favicon.ico"
}
]
}

导入后可以看到 12 个网址集中呈现在 Dashlet 首页:

这里最值得理解的不是"导入成功"四个字,而是配置与界面的对应关系:name 决定标题,description 提供简短说明,url 指向真正要打开的网站,icon 控制图标来源。如果将 url 改成 NAS 的内网地址,那么外出时即使能打开 Dashlet 首页,点击这个内网地址也仍然需要相应的网络访问条件。
5. 哪些配置项真正影响使用体验
示例里的 theme: "system" 使用跟随系统的主题,accentColor、blur 和 animations 影响颜色与视觉效果;wallpaper 可以配置背景,layout: "list" 决定展示方式。openNewTab: true 让服务在新标签页打开,适合把 Dashlet 留作固定起点。
查找入口时可以关注 searchEnabled、searchProvider 与 sortBy。这份配置使用 DuckDuckGo 作为搜索网址,sortBy: "manual" 表示手动排序,disableDragDrop: false 则保留拖拽能力。它们让网址清单更容易维护,但并不代表已经接入各个网站内部的搜索数据。
customCSS 以及自定义 JavaScript 属于进一步扩展界面的能力。若要放到长期使用的私人首页,我会先把网址和配置核对好,再考虑样式和脚本;尤其是把页面开放到公网时,不适合在配置里放入密码、令牌等敏感信息。示例中的图标还引用了外部网站资源,页面因此不等于完全离线运行。
6. 安装 cpolar,为 8989 增加一个远程入口
本地访问正常以后,再考虑从手机或异地电脑打开导航页。这里使用 cpolar 映射极空间上的 Dashlet Web 服务,它负责公网入口,不负责替各个 services.url 建立独立的网络通道。
先执行安装命令:
shell
sudo curl https://get.cpolar.sh | sh

安装完成后检查 cpolar 服务:
shell
sudo systemctl status cpolar

然后通过极空间的局域网 IP 加 9200 访问 cpolar Web 管理界面,使用已注册的账号登录:

注意区分两个端口:9200 是 cpolar 管理界面,Dashlet 实际运行在 8989。后面创建隧道要填写的是后者。
7. 先用随机域名确认公网链路
进入 隧道管理 → 创建隧道 ,按照本次示例填写:隧道名 dashlet,协议 http,本地地址 8989,域名类型选择随机域名,地区选 China Top。

创建后进入在线隧道列表,查看分配的公网地址:

使用另一台设备访问该地址:

当 Dashlet 页面能够在外网正常打开时,才说明"外部设备 → cpolar → 极空间 8989"这条链路已经走通。随机地址更适合临时验证;如果后续准备把它当作固定书签,再配置二级子域名会省去重复更换入口的麻烦。
8. 预留固定二级子域名并更新隧道
进入 cpolar 的预留页面,选择 保留二级子域名:

本次演示地区选 china Top,预留名称填写 dashlet。子域名需要以自己的账号实际保留成功为准,不能默认每个人都能使用同一个名称。

随后回到 隧道管理 → 隧道列表,找到对应隧道并点击编辑:

把域名类型改为二级子域名,在 Sub Domain 中填写已保留的名称,地区选 China Top,点击更新:

再进入在线隧道列表,确认公网地址已经切换为固定二级子域名形式:

最后在外部浏览器访问新地址,确认 Dashlet 首页仍能打开:

固定地址解决的是入口变化的问题,实际可用性仍取决于极空间、Dashlet 容器、cpolar 服务和网络连接是否持续正常;能否保留对应子域名,也以账号权益和预留结果为准。
9. 分享这个首页之前,先检查链接和访问边界
把 Dashlet 用作私人入口时,我会先逐个点开配置中的链接。公网首页不应泄露不打算公开的内网管理地址、设备信息或敏感参数;即使列表中只显示了网址,也不能把公开仪表盘误当成一道访问控制。某个应用是否需要登录、能否被外网访问,应由它自己的权限设置和网络条件决定。
这份演示真正验证了三个环节:Dashlet 在极空间 8989 运行、12 个示例网址可以导入并呈现、cpolar 能把主页从随机公网入口切到固定二级子域名。后续再增加 NAS 应用时,按照同一套配置方式维护即可,不必让所有服务共享同一套授权边界。
总结
Dashlet 适合解决一个很具体的小问题:NAS 上的服务越来越多,能不能把常用入口整理成一张自己愿意每天打开的首页。用 Docker 部署以后,通过 config.json 维护网址、图标、主题和顺序;用 cpolar 连接本地 8989,又能在外出时找到这个统一入口。
把导航页和监控系统的职责分清,把公网地址和每个应用的访问权限分清,这套轻量的私人仪表盘才会既好找、好改,也更容易长期使用。