1. 项目概述:为什么你需要一个个人导航页?
在信息爆炸的今天,我们每天要面对数十个甚至上百个常用链接:工作用的项目管理工具、内部系统、代码仓库;学习用的技术文档、在线课程;生活用的购物网站、社交媒体、家庭智能设备控制台。把这些链接一股脑地塞进浏览器书签栏,结果往往是混乱不堪、难以查找。更别提当你需要在不同设备间同步时,那份手忙脚乱。一个集中、美观、可自定义的个人导航页,就成了提升数字生活效率的刚需。
Homepage,正是这样一个为技术爱好者量身打造的开源个人导航页项目。它远不止是一个简单的链接集合页面。你可以把它理解为你个人数字世界的“控制中心”或“仪表盘”。它允许你将所有重要的网页链接、服务状态、甚至智能家居设备、服务器监控信息,都以小组件(Widget)的形式,优雅地聚合在一个页面上。通过Docker容器化部署,你可以在自己的Linux服务器、NAS甚至树莓派上快速搭建起这个专属门户,实现完全的数据私有化,无需依赖任何第三方服务。
对于Linux用户和开发者而言,部署Homepage的过程本身也是一次绝佳的实践。它涉及Docker容器管理、反向代理配置、服务发现等现代运维的基础技能。无论你是想打造一个高效的工作流入口,还是想拥有一个酷炫的私人主页来展示你的技术栈,Homepage都是一个值得投入的周末项目。接下来,我将带你从零开始,在Linux系统上完整部署并深度定制你的Homepage。
2. 整体设计与环境准备
2.1 核心架构与方案选型
Homepage的设计哲学是“轻量、模块化、可扩展”。其核心是一个用TypeScript编写的Web应用,后端逻辑相对简单,主要提供配置文件的读取和API接口。因此,官方推荐且最主流的部署方式就是使用Docker Compose。为什么是Docker Compose而不是直接运行Node.js应用?
首先,依赖隔离与一致性。Homepage依赖于特定的Node.js环境及其npm包。使用Docker镜像(ghcr.io/benphelps/homepage:latest)可以确保在任何Linux发行版上运行的环境完全一致,避免了“在我机器上好好的”这类问题。你不需要在宿主机上安装Node.js、管理npm版本或处理潜在的依赖冲突。
其次,配置与数据持久化。Homepage的所有自定义内容——包括导航链接、服务小组件、主题样式——都通过YAML配置文件来定义。Docker Compose方案通过“卷挂载”(Volume Mount)的方式,将宿主机的配置文件目录映射到容器内部。这样做的好处是:你的所有配置数据都保留在宿主机上,即使删除并重新创建容器,配置也不会丢失。更新Homepage版本时,只需拉取新镜像并重启容器,配置会自动加载,迁移成本为零。
最后,与周边生态无缝集成。许多现代自托管服务(如Portainer、Uptime Kuma、AdGuard Home等)都提供了API。Homepage可以通过配置,主动查询这些服务的状态并显示在页面上。将这些服务与Homepage放在同一个Docker网络中,可以简化内部服务发现和通信。
基于以上考量,我们的部署方案确定为:使用Docker Compose部署Homepage容器,并通过Nginx Proxy Manager(NPM)进行反向代理和HTTPS证书管理。NPM提供了友好的Web界面来管理域名、SSL证书和代理规则,比直接配置Nginx更直观,尤其适合新手。
2.2 基础环境检查与工具安装
在开始之前,请确保你拥有一台运行Linux的服务器(如Ubuntu 22.04 LTS、Debian 11、CentOS Stream 9等)并已具备SSH访问权限。我们将以具有sudo权限的用户进行操作。
第一步:更新系统并安装基础工具这是一个好习惯,可以确保软件源和系统包是最新的。
sudo apt update && sudo apt upgrade -y # Ubuntu/Debian # 或者 sudo dnf update -y # Fedora/Rocky Linux/CentOS Stream安装一些后续可能用到的工具:
sudo apt install -y curl wget git vim # Ubuntu/Debian第二步:安装Docker Engine和Docker Compose PluginDocker Compose Plugin是Docker官方推荐的现代方式,它通过docker compose命令来替代旧的docker-compose独立二进制文件。
对于Ubuntu/Debian系统:
# 1. 卸载旧版本(如有) sudo apt remove docker docker-engine docker.io containerd runc # 2. 安装依赖包,允许apt通过HTTPS使用仓库 sudo apt install -y ca-certificates curl gnupg # 3. 添加Docker官方GPG密钥 sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg # 4. 设置Docker稳定版仓库 echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # 5. 安装Docker Engine和Compose Plugin sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # 6. 验证安装 docker --version docker compose version对于RHEL系(如Rocky Linux)系统,步骤类似,需使用yum或dnf并添加对应的仓库。
第三步:(可选但推荐)安装Nginx Proxy Manager我们将使用NPM来管理域名和SSL。同样使用Docker Compose部署。 创建一个专用目录并编写docker-compose.yml:
mkdir -p ~/nginx-proxy-manager && cd ~/nginx-proxy-manager vim docker-compose.yml将以下内容粘贴进去:
version: '3.8' services: app: image: 'jc21/nginx-proxy-manager:latest' container_name: nginx-proxy-manager restart: unless-stopped ports: - '80:80' # HTTP端口 - '81:81' # 管理界面端口 - '443:443' # HTTPS端口 volumes: - ./data:/data - ./letsencrypt:/etc/letsencrypt networks: - npm-network networks: npm-network: driver: bridge保存并启动:
docker compose up -d启动后,在浏览器访问http://你的服务器IP:81。默认登录邮箱为admin@example.com,密码为changeme。首次登录会强制修改密码和邮箱。
注意:如果你的服务器80/443端口已被占用(例如已有Nginx或Apache),你需要先停止这些服务或修改NPM的映射端口(如
8080:80,8443:443),但这样会影响标准HTTP/HTTPS访问。最佳实践是让NPM独占80/443端口,由它来统一代理所有Web服务。
3. Homepage部署与基础配置
3.1 创建项目结构与配置文件
Homepage的配置全部通过YAML文件完成,结构清晰。我们首先创建标准的目录结构来存放所有配置。
# 在用户目录下创建homepage文件夹 mkdir -p ~/homepage cd ~/homepage # 创建核心配置目录 mkdir -p ~/homepage/config # 创建子目录,用于存放不同类型的配置 mkdir -p ~/homepage/config/{services,bookmarks,settings,widgets}这个结构不是强制的,但官方推荐且易于管理:
config/: 主配置目录。config/services/: 存放“服务”小组件的配置,每个服务一个YAML文件。config/bookmarks/: 存放书签导航的配置,可按分类创建多个YAML文件。config/settings.yaml: 主页全局设置,如标题、主题、布局等。config/widgets/: 存放其他类型小组件的配置,如天气、系统状态等。
3.2 编写Docker Compose文件
在~/homepage目录下创建docker-compose.yml文件:
vim docker-compose.yml输入以下内容:
version: '3.8' services: homepage: image: ghcr.io/benphelps/homepage:latest container_name: homepage restart: unless-stopped ports: - "3000:3000" # 将容器内3000端口映射到宿主机3000端口 volumes: # 挂载配置文件目录 - ./config:/app/config # 挂载图标缓存目录,加速图标加载 - ./icons:/app/public/icons # 可选:挂载自定义CSS/JS目录,用于深度美化 - ./custom:/app/custom environment: # 设置容器内时区,确保时间显示正确 - TZ=Asia/Shanghai networks: - default # 使用默认网络,如果需与其他容器通信,可创建自定义网络 # 无需额外定义网络,使用默认即可这个配置做了几件事:
- 使用官方最新镜像。
- 设置容器自动重启,保证服务高可用。
- 将宿主机
~/homepage/config目录映射到容器的/app/config,这是Homepage读取配置的地方。 - 映射了一个
icons目录,用于缓存从网络获取的网站图标(Favicon),避免每次刷新都重新下载。 - 设置了时区环境变量。
保存文件后,启动Homepage容器:
docker compose up -d使用docker logs homepage查看启动日志,确认没有报错。此时,访问http://你的服务器IP:3000应该能看到一个非常简洁的、带有默认“Welcome”信息的Homepage界面。这说明基础服务已经跑起来了,但还没有任何自定义内容。
3.3 配置基础设置与主题
现在我们来创建第一个配置文件:全局设置。编辑~/homepage/config/settings.yaml:
vim ~/homepage/config/settings.yaml一个基础且实用的配置如下:
--- # Homepage 全局设置 title: "我的数字工作台" # 页面标题 footer: "Powered by Homepage • 自托管于我的服务器" # 页脚信息 # 布局与外观 layout: # 页面主体最大宽度,'xl'较宽,'lg'适中 pageMaxWidth: 'xl' # 是否启用搜索栏 search: true # 是否启用主题切换按钮(浅色/深色) themeToggle: true # 主题配置 theme: # 默认主题,可选:light, dark, auto (跟随系统) default: auto # 自定义颜色(可选) colors: primary: '#3b82f6' # 主色调,蓝色 # 搜索引擎设置(用于顶部的搜索框) search: # 默认搜索引擎 defaultProvider: google providers: - name: google url: https://www.google.com/search?q= - name: bing url: https://www.bing.com/search?q= - name: github url: https://github.com/search?q= # 头部导航栏 header: enabled: true # 可以在这里定义一些全局链接,如文档、仪表盘等 items: - name: 服务器状态 icon: mdi:server url: /server-stats # 可以指向一个内部小组件或外部链接 # 是否在服务卡片上显示图标 showServiceIcons: true保存后,刷新Homepage页面(http://IP:3000),你应该能看到页面标题、搜索框和主题切换按钮已经生效。主题切换为auto时,页面会跟随你操作系统的深色/浅色模式自动切换。
4. 核心功能配置详解
4.1 服务(Services)小组件配置
服务小组件是Homepage的核心,它以一个美观的卡片形式展示你自托管或常用的网络服务,并可以显示其运行状态(在线/离线)。配置存放在config/services/目录下,你可以按类别分文件存放。
让我们创建一个开发工具类的服务配置。编辑~/homepage/config/services/development.yaml:
vim ~/homepage/config/services/development.yaml--- # 开发工具服务组 - name: Portainer # 服务显示名称 description: Docker容器管理 # 描述信息 icon: portainer.png # 图标文件名(需放在/icons目录)或 icon: mdi:docker 使用Material Design图标 href: https://portainer.my-domain.com # 服务访问地址 widget: # 状态查询部件 type: http # 类型为HTTP请求 url: https://portainer.my-domain.com/api/status # 服务的健康检查API端点 interval: 60 # 检查间隔,单位秒 # 可选:设置请求头,如果服务需要认证 # headers: # Authorization: Bearer your-api-key-here - name: Gitea description: 自托管Git服务 icon: mdi:git href: https://git.my-domain.com widget: type: http url: https://git.my-domain.com/api/v1/version interval: 120 - name: Jenkins description: CI/CD 自动化服务器 icon: mdi:jenkins href: https://jenkins.my-domain.com widget: type: http url: https://jenkins.my-domain.com/login # Jenkins可能没有专门的健康API,检查登录页面返回状态码是否为200 statusCodeCheck: true interval: 90配置解析与技巧:
- 图标(icon):优先使用Material Design Icons(格式如
mdi:git),Homepage内置支持,无需额外下载。如果服务有独特图标,可以将其PNG文件放入~/homepage/icons/目录,然后引用文件名(如portainer.png)。你可以从服务的官方网站获取favicon.ico,然后转换为PNG格式。 - 状态检查(widget):
type: http是最常用的方式,向服务的某个API或页面发起GET请求。url应指向一个能快速返回、无需认证(或已配置认证头)的端点。许多自托管应用都有/api/health、/api/status或/version这样的端点。statusCodeCheck: true是一个简便方法,它只检查HTTP响应状态码是否为2xx,不解析返回内容。适合没有标准健康API但网页可访问的服务。interval不宜设置过短,避免对服务造成不必要的负载,通常60-300秒即可。
- 分组与排序:你可以在
settings.yaml中通过services字段控制服务组的排序和显示。但更简单的做法是,通过文件名来隐式控制,因为Homepage会按文件名字母顺序加载services/目录下的YAML文件。例如,0-essential.yaml会排在development.yaml前面。
4.2 书签(Bookmarks)导航配置
书签用于组织那些不需要状态检查的纯链接,比如技术文档、常用网站、工具等。配置存放在config/bookmarks/目录下。
创建一个工作常用书签的配置,编辑~/homepage/config/bookmarks/work.yaml:
vim ~/homepage/config/bookmarks/work.yaml--- # 工作相关书签 - 开发: - 项目文档: - 内部Wiki: href: https://wiki.company.com icon: mdi:book-open-variant - API 规范: href: https://swagger.company.com icon: mdi:api - 代码仓库: - GitHub: href: https://github.com icon: mdi:github - GitLab: href: https://gitlab.com icon: mdi:gitlab - 协作工具: - Jira: href: https://team.atlassian.net icon: mdi:jira - Slack: href: https://slack.com icon: mdi:slack - 飞书: href: https://feishu.cn icon: feishu.png # 自定义图标 - 运维监控: - 服务器仪表盘: - Grafana: href: https://grafana.my-domain.com icon: mdi:chart-areaspline - Prometheus: href: https://prom.my-domain.com icon: mdi:chart-timeline - 日志系统: - Loki: href: https://loki.my-domain.com icon: mdi:file-document-outline - Kibana: href: https://kibana.my-domain.com icon: mdi:file-search-outline书签配置采用嵌套结构,支持无限级分类,这让你可以构建一个非常清晰的信息树。图标同样支持MDI和自定义图片。
4.3 其他小组件配置
Homepage还支持多种信息型小组件,如天气、系统资源监控、RSS订阅等。这些通常配置在config/widgets/目录或直接在settings.yaml中。
例如,添加一个系统资源监控小组件(需要安装glances等监控工具并启用其API)。首先,在settings.yaml的widgets部分添加:
widgets: - resources: # 资源监控 cpu: true memory: true disk: / # 监控根分区 host: glances # 假设glances容器名或服务名 port: 61208 # glances API端口 interval: 10 - iframe: # 嵌入一个内部页面 url: http://localhost:8080 # 例如,另一个内部服务的简单状态页 title: 内部服务面板 height: 400px - search: # 搜索栏,可以单独作为一个小组件放置 - datetime: # 日期时间 format: 'YYYY-MM-DD HH:mm:ss' timezone: Asia/Shanghai天气小组件需要注册一个OpenWeatherMap的API Key,配置相对复杂但文档详细。这些小组件能极大地丰富主页的信息密度和实用性。
5. 通过反向代理配置域名与HTTPS
直接通过IP和端口访问既不安全也不方便。我们需要通过之前部署的Nginx Proxy Manager(NPM)来绑定域名并启用HTTPS。
第一步:配置DNS解析在你的域名管理后台(如Cloudflare、阿里云DNS),添加一条A记录,将你想要的子域名(例如homepage.yourdomain.com)解析到你的服务器公网IP地址。
第二步:在NPM中添加代理主机
- 浏览器访问NPM管理界面(
http://你的服务器IP:81),使用修改后的管理员账号登录。 - 点击顶部菜单的“Hosts” -> “Proxy Hosts”,然后点击“Add Proxy Host”。
- 填写代理配置:
- Details 标签页:
- Domain Names:
homepage.yourdomain.com(你刚解析的域名) - Scheme:
http - Forward Hostname / IP:
homepage(这是Homepage的Docker容器名,因为NPM和Homepage在同一个Docker宿主机上,且默认网络互通,可以直接用容器名访问。如果不在同一主机,则填服务器内网IP。) - Forward Port:
3000(Homepage容器内部端口)
- Domain Names:
- SSL 标签页:
- SSL Certificate: 选择 “Request a new SSL Certificate”
- 勾选 “Force SSL” 和 “HTTP/2 Support”
- 勾选 “I agree to the Let's Encrypt Terms of Service”
- 邮箱填写你的有效邮箱(用于证书到期提醒)
- Details 标签页:
- 点击“Save”。NPM会自动向Let‘s Encrypt申请免费的SSL证书,通常几十秒内即可完成。
第三步:验证访问证书申请成功后,你应该可以直接通过https://homepage.yourdomain.com安全地访问你的个人导航页了。浏览器地址栏会显示安全的锁标志。
重要提示:防火墙配置。确保你的服务器安全组或防火墙(如
ufw)已放行80和443端口,这是NPM对外提供服务所必需的。如果之前为了测试映射了3000端口到公网,现在可以关闭它,以增强安全性。sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw deny 3000/tcp # 或直接删除之前的3000端口规则 sudo ufw reload
6. 高级定制与优化技巧
6.1 深度美化:自定义CSS与JS
Homepage的默认主题已经很美观,但你可能想微调颜色、间距或添加一些动态效果。这可以通过挂载自定义资源文件实现。
在docker-compose.yml中,我们已经将宿主机的./custom目录挂载到了容器的/app/custom。现在,在这个目录下创建CSS和JS文件:
mkdir -p ~/homepage/custom cd ~/homepage/custom vim custom.css在custom.css中添加你的样式,例如:
/* 修改卡片悬停阴影效果 */ .service-card, .bookmark-card { transition: transform 0.2s ease, box-shadow 0.2s ease; } .service-card:hover, .bookmark-card:hover { transform: translateY(-4px); box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.15); } /* 修改头部背景为渐变 */ header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); } /* 自定义滚动条样式 */ ::-webkit-scrollbar { width: 8px; } ::-webkit-scrollbar-track { background: #f1f1f1; border-radius: 4px; } ::-webkit-scrollbar-thumb { background: #888; border-radius: 4px; } ::-webkit-scrollbar-thumb:hover { background: #555; }然后,在settings.yaml中引用这个CSS文件:
--- # ... 其他设置 ... custom: css: /app/custom/custom.css # js: /app/custom/custom.js # 如果需要自定义JS也可以这样引入重启Homepage容器使配置生效:docker compose restart homepage。刷新页面,就能看到自定义样式已经应用。
6.2 自动化图标获取与缓存
手动为每个服务寻找和下载图标非常耗时。Homepage社区有一个非常棒的工具叫homepage-icons,它可以自动从网站抓取图标并缓存到本地。
你可以编写一个简单的Shell脚本,定期运行(例如通过cron定时任务)来更新图标库。脚本思路是:遍历你的所有服务配置,提取href字段中的域名,然后使用工具(如curl配合python的beautifulsoup4,或专门的favicon下载器)去获取该域名的图标,并保存到~/homepage/icons/目录下,命名为域名.png。在服务配置中,icon字段就可以直接写domain.com.png。
虽然这需要一些脚本编写能力,但一劳永逸。社区也有用户分享了他们的脚本,可以在Homepage的GitHub Discussions中搜索“icon script”找到参考。
6.3 集成更多服务状态
Homepage的强大之处在于它能集成大量服务的“动态状态”。除了简单的HTTP状态码检查,许多流行应用有更丰富的集成方式:
- Docker容器状态:通过集成
docker.sock(需谨慎处理权限和安全)或Portainer API,可以直接显示哪些容器在运行。 - Ping监控:使用
ping类型的widget,可以监控任何网络设备的可达性。 - API响应解析:对于返回JSON的健康检查接口,你可以配置
widget的key字段来解析特定JSON路径的值,并根据该值判断服务状态(如"status": "UP")。 - 智能家居:通过集成Home Assistant的API,可以直接在Homepage上显示传感器数据、控制开关。
这些高级配置需要查阅Homepage的官方文档中关于Widgets的详细说明,但原理都是相通的:找到服务的状态查询端点,配置正确的请求方法和响应解析规则。
7. 常见问题与故障排查实录
在部署和配置过程中,你可能会遇到以下问题。这里记录了我踩过的坑和解决方案。
问题1:访问Homepage页面显示“Cannot GET /config”或空白页。
- 原因:配置文件路径挂载错误或配置文件语法有误(YAML格式错误)。
- 排查:
- 进入容器检查:
docker exec -it homepage sh,然后ls -la /app/config,看配置文件是否存在。 - 检查YAML语法:YAML对缩进非常敏感,必须使用空格,不能使用Tab。可以使用在线YAML校验器检查你的配置文件。
- 查看容器日志:
docker logs --tail 50 homepage,通常会有具体的错误信息提示哪一行配置出错。
- 进入容器检查:
问题2:服务状态卡片一直显示“Loading...”或“Unknown”。
- 原因:状态检查请求失败。可能是网络不通、URL错误、SSL证书问题或需要认证。
- 排查:
- 从宿主机测试连通性:在宿主机上运行
curl -v https://portainer.my-domain.com/api/status,看是否能收到200响应。如果curl失败,说明问题出在网络或服务本身。 - 检查容器网络:确保Homepage容器能访问到目标服务。如果目标服务也在同一台宿主机上的Docker容器中,最好将它们连接到同一个自定义Docker网络,并使用容器名作为主机名进行访问。
- 忽略SSL证书错误(仅测试):对于自签名证书的服务,可以在widget配置中添加
insecure: true来跳过证书验证(生产环境不推荐)。 - 配置认证头:如果状态API需要认证,务必在
widget部分正确配置headers。
- 从宿主机测试连通性:在宿主机上运行
问题3:通过NPM访问HTTPS域名,页面能打开但样式错乱或API请求失败。
- 原因:Homepage应用内部可能还在使用HTTP链接生成资源路径,而页面是通过HTTPS加载的,导致混合内容(Mixed Content)被浏览器阻止。
- 解决:在Homepage的
docker-compose.yml中,为容器添加一个环境变量,告诉它外部访问的协议和域名。
然后重启容器。这能确保Homepage生成的资源链接(如图标、API请求)都是正确的HTTPS地址。environment: - TZ=Asia/Shanghai - HOMEPAGE_HOST_URL=https://homepage.yourdomain.com # 添加这一行
问题4:图标不显示,显示为默认链接图标。
- 原因:图标路径错误或图标文件不存在。
- 排查:
- 如果使用MDI图标(如
mdi:github),确保名称正确。可以到 Material Design Icons 网站 搜索确认。 - 如果使用自定义图标(如
github.png),确保文件确实存在于~/homepage/icons/目录下,并且文件名与配置中引用的完全一致(包括大小写)。 - 检查图标目录的挂载:在容器内查看
/app/public/icons目录下是否有文件。
- 如果使用MDI图标(如
问题5:更新Homepage镜像后,配置丢失或页面报错。
- 原因:
docker compose up -d会重新创建容器,如果卷挂载配置错误,或者使用了匿名卷,数据就会丢失。 - 预防与解决:
- 绝对确保使用命名卷或绑定挂载(我们用的就是绑定挂载
./config:/app/config)。这是数据持久化的生命线。 - 更新前,可以先执行
docker compose pull拉取新镜像,然后docker compose up -d重启。Compose会重用已有的卷。 - 建议将整个
~/homepage目录纳入版本控制系统(如Git),这样即使宿主机磁盘损坏,配置也有备份。
- 绝对确保使用命名卷或绑定挂载(我们用的就是绑定挂载
部署Homepage的过程,就像在精心布置一个数字化的家。从最初的空房间(空白页面),到添置家具(添加服务卡片和书签),再到安装智能控制系统(配置状态检查和小部件),每一步都让这个空间变得更高效、更个性化。它不仅仅是一个导航页,更是你个人技术栈和数字习惯的集中体现。当你把所有碎片化的入口整合到一个响应迅速、界面优雅的页面上时,那种掌控感和流畅感,会实实在在地提升你每一天的数字化工作效率。