Compare commits
No commits in common. "860725a9bb193fad2ce217676d6962ca24076556" and "b888d6b6409f50eea604270d5d7ff404ea197d08" have entirely different histories.
860725a9bb
...
b888d6b640
2 changed files with 0 additions and 423 deletions
|
|
@ -1,205 +0,0 @@
|
||||||
---
|
|
||||||
title: Docker Template
|
|
||||||
description: Swarm and Compose Template
|
|
||||||
published: true
|
|
||||||
date: 2026-04-10T19:53:21.433Z
|
|
||||||
tags:
|
|
||||||
editor: markdown
|
|
||||||
dateCreated: 2026-04-10T19:53:21.433Z
|
|
||||||
---
|
|
||||||
|
|
||||||
# Docker Swarm Template Standard — Netgrimoire
|
|
||||||
|
|
||||||
## Template
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# Run with docker stack deploy -c <service>.yaml <service>
|
|
||||||
services:
|
|
||||||
<servicename>:
|
|
||||||
image: <image>:latest
|
|
||||||
environment:
|
|
||||||
TZ: America/Chicago
|
|
||||||
volumes:
|
|
||||||
- /DockerVol/<servicename>:/config # use WITH placement constraint
|
|
||||||
# - /data/nfs/znas/Docker/<servicename>:/data # use for bulk/data or no constraint
|
|
||||||
networks:
|
|
||||||
- netgrimoire
|
|
||||||
deploy:
|
|
||||||
restart_policy:
|
|
||||||
condition: any
|
|
||||||
delay: 5s
|
|
||||||
max_attempts: 3
|
|
||||||
window: 120s
|
|
||||||
placement:
|
|
||||||
constraints:
|
|
||||||
- node.platform.arch != aarch64
|
|
||||||
- node.platform.arch != arm
|
|
||||||
labels:
|
|
||||||
# --- Caddy ---
|
|
||||||
caddy: <servicename>.netgrimoire.com
|
|
||||||
caddy.reverse_proxy: <servicename>:<PORT>
|
|
||||||
caddy.import: crowdsec
|
|
||||||
caddy.import_1: authentik
|
|
||||||
|
|
||||||
# --- Uptime Kuma ---
|
|
||||||
kuma.<servicename>.http.name: <Service Name>
|
|
||||||
kuma.<servicename>.http.url: https://<servicename>.netgrimoire.com
|
|
||||||
|
|
||||||
# --- Homepage ---
|
|
||||||
homepage.group: <Group>
|
|
||||||
homepage.name: <Service Name>
|
|
||||||
homepage.icon: <service>.png
|
|
||||||
homepage.href: https://<servicename>.netgrimoire.com
|
|
||||||
homepage.description: <Description>
|
|
||||||
|
|
||||||
# --- DIUN ---
|
|
||||||
diun.enable: "true"
|
|
||||||
|
|
||||||
networks:
|
|
||||||
netgrimoire:
|
|
||||||
external: true
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Rules
|
|
||||||
|
|
||||||
### Forbidden Fields
|
|
||||||
Never use these at the service level:
|
|
||||||
- `version:` — deprecated in Compose v2+
|
|
||||||
- `container_name:` — incompatible with Swarm replicas
|
|
||||||
- `restart:` — use `deploy.restart_policy` instead
|
|
||||||
- `depends_on:` — not supported in Swarm mode
|
|
||||||
|
|
||||||
### Volume Path Rules
|
|
||||||
|
|
||||||
| Path | When to Use |
|
|
||||||
|------|------------|
|
|
||||||
| `/DockerVol/<service>` | Config/state files. **Only valid when a placement constraint pins the service to a specific host.** |
|
|
||||||
| `/data/nfs/znas/Docker/<service>` | Data/bulk volumes, or any service without a specific hostname constraint |
|
|
||||||
|
|
||||||
### Caddy Labels
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
caddy: service.netgrimoire.com
|
|
||||||
caddy.reverse_proxy: servicename:PORT
|
|
||||||
caddy.import: crowdsec
|
|
||||||
caddy.import_1: authentik
|
|
||||||
```
|
|
||||||
|
|
||||||
- `caddy.import_1` is required for the second import — duplicate YAML keys cause deploy errors
|
|
||||||
- `caddy.reverse_proxy` uses `servicename:PORT` (internal Docker DNS), never `{{upstreams PORT}}`
|
|
||||||
- No `https://` prefix on the `caddy:` address line
|
|
||||||
- Services managed by Caddyfile (static config) must **not** also have Caddy Docker labels — mixing causes caddy-docker-proxy to merge them into a malformed upstream pool
|
|
||||||
|
|
||||||
### Networking
|
|
||||||
|
|
||||||
- Default VIP mode for services that publish ports
|
|
||||||
- `endpoint_mode: dnsrr` for internal-only services (no published ports) — avoids Swarm VIP stale DNS
|
|
||||||
- **Never use `dnsrr` on services with published ports** — incompatible with ingress mesh routing
|
|
||||||
|
|
||||||
### Placement Constraints
|
|
||||||
|
|
||||||
**Architecture exclusions** (always include unless ARM-specific):
|
|
||||||
```yaml
|
|
||||||
constraints:
|
|
||||||
- node.platform.arch != aarch64 # Pi 4 reports aarch64
|
|
||||||
- node.platform.arch != arm # Pi 3 reports arm
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note:** Docker Swarm uses the kernel's arch string. Pi 4 reports `aarch64` not `arm64`. The constraint `!= arm64` does **not** exclude Pi 4s.
|
|
||||||
|
|
||||||
Verified node architectures in Netgrimoire:
|
|
||||||
```
|
|
||||||
DockerPi1: linux/aarch64
|
|
||||||
docker3: linux/x86_64
|
|
||||||
docker4: linux/x86_64
|
|
||||||
docker5: linux/x86_64
|
|
||||||
znas: linux/x86_64
|
|
||||||
```
|
|
||||||
|
|
||||||
### Label Sections
|
|
||||||
|
|
||||||
Labels are organized with comment dividers in this order:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
labels:
|
|
||||||
# --- Caddy ---
|
|
||||||
# --- Uptime Kuma ---
|
|
||||||
# --- Homepage ---
|
|
||||||
# --- DIUN ---
|
|
||||||
```
|
|
||||||
|
|
||||||
Use map syntax (not list syntax) for labels. List syntax (`- key=value`) and map syntax (`key: value`) both work, but map syntax is the standard.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Services Without a UI
|
|
||||||
|
|
||||||
Some services have no web interface and need no Caddy, Homepage, or Kuma labels:
|
|
||||||
|
|
||||||
**Example: DIUN**
|
|
||||||
```yaml
|
|
||||||
deploy:
|
|
||||||
labels:
|
|
||||||
# --- DIUN ---
|
|
||||||
diun.enable: "true"
|
|
||||||
```
|
|
||||||
|
|
||||||
Services in this category: DIUN, background workers, one-shot jobs.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Kuma Label Format
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
kuma.<unique-id>.<monitor-type>.<field>: <value>
|
|
||||||
```
|
|
||||||
|
|
||||||
- `unique-id` — must be unique across all services in the entire Swarm
|
|
||||||
- `monitor-type` — `http`, `tcp`, `ping`, `dns`
|
|
||||||
- Common fields: `name`, `url`, `interval`, `maxretries`
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```yaml
|
|
||||||
kuma.forgejo.http.name: Forgejo
|
|
||||||
kuma.forgejo.http.url: https://git.netgrimoire.com
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Homepage Label Format
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
homepage.group: Group Name
|
|
||||||
homepage.name: Display Name
|
|
||||||
homepage.icon: icon.png
|
|
||||||
homepage.href: https://service.netgrimoire.com
|
|
||||||
homepage.description: Short description
|
|
||||||
```
|
|
||||||
|
|
||||||
For services with widgets:
|
|
||||||
```yaml
|
|
||||||
homepage.widget.type: radarr
|
|
||||||
homepage.widget.url: http://radarr:7878
|
|
||||||
homepage.widget.key: apikey
|
|
||||||
```
|
|
||||||
|
|
||||||
**Important:** Every `homepage.group` value must have a matching entry in `settings.yaml` with `style: column`, or the group will render full-width.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Secrets Approach
|
|
||||||
|
|
||||||
Docker Swarm native secrets are preferred. For services that support `_FILE` env vars:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
environment:
|
|
||||||
MY_PASSWORD_FILE: /run/secrets/my_password
|
|
||||||
secrets:
|
|
||||||
- my_password
|
|
||||||
```
|
|
||||||
|
|
||||||
Plain credentials in environment vars are acceptable as an interim approach for services that don't support `_FILE`.
|
|
||||||
|
|
||||||
**Never use `env_file:` in Swarm stacks** — it's read by the Docker client at deploy time from the deploying machine, not injected into the container at runtime. Use `environment:` directly.
|
|
||||||
|
|
@ -1,218 +0,0 @@
|
||||||
---
|
|
||||||
title: Homepage Final Config
|
|
||||||
description:
|
|
||||||
published: true
|
|
||||||
date: 2026-04-10T19:50:17.672Z
|
|
||||||
tags:
|
|
||||||
editor: markdown
|
|
||||||
dateCreated: 2026-04-10T19:50:17.672Z
|
|
||||||
---
|
|
||||||
|
|
||||||
# Homepage Configuration — Netgrimoire Command Center
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Homepage (`ghcr.io/gethomepage/homepage`) runs as a Docker Swarm service on `znas`, pinned to port `3056:3000` and accessible at `https://homepage.netgrimoire.com`.
|
|
||||||
|
|
||||||
Config files live at `/DockerVol/homepage/config/`. Images live at `/DockerVol/homepage/images/` (mounted as `/app/public/images:ro`).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Tab Structure
|
|
||||||
|
|
||||||
| Tab | Groups |
|
|
||||||
|-----|--------|
|
|
||||||
| Glance | Glance (iframe) |
|
|
||||||
| Netgrimoire | Applications, Gremlin, Monitoring, Management, Backup, Mail Services, Remote Access, Services |
|
|
||||||
| PNCHarris | PNCHarris Apps |
|
|
||||||
| Wasted-Bandwidth | Jolly Roger, Downloaders, VPN Protected Apps, Media Management, Media Search |
|
|
||||||
| Nucking-Futz | Nucking Apps, Entertainment |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Compose File
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# swarm/homepage.yaml
|
|
||||||
services:
|
|
||||||
homepage:
|
|
||||||
image: ghcr.io/gethomepage/homepage:latest
|
|
||||||
environment:
|
|
||||||
- HOMEPAGE_ALLOWED_HOSTS=homepage.netgrimoire.com,glance.netgrimoire.com
|
|
||||||
- HOMEPAGE_VAR_MAILCOW_KEY=<mailcow-api-key>
|
|
||||||
- HOMEPAGE_VAR_DNS_TOKEN=<technitium-token>
|
|
||||||
- HOMEPAGE_VAR_OPNSENSE_USER=<opnsense-api-key>
|
|
||||||
- HOMEPAGE_VAR_OPNSENSE_PASS=<opnsense-api-secret>
|
|
||||||
- HOMEPAGE_VAR_IMMICH_KEY=<immich-api-key>
|
|
||||||
ports:
|
|
||||||
- 3056:3000
|
|
||||||
volumes:
|
|
||||||
- /DockerVol/homepage/config:/app/config
|
|
||||||
- /DockerVol/homepage/images:/app/public/images:ro
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
||||||
networks:
|
|
||||||
- netgrimoire
|
|
||||||
deploy:
|
|
||||||
placement:
|
|
||||||
constraints:
|
|
||||||
- node.hostname == znas
|
|
||||||
labels:
|
|
||||||
caddy: homepage.netgrimoire.com
|
|
||||||
caddy.reverse_proxy: homepage:3000
|
|
||||||
caddy.import: crowdsec
|
|
||||||
caddy.import_1: authentik
|
|
||||||
kuma.homepage.http.name: Homepage
|
|
||||||
kuma.homepage.http.url: https://homepage.netgrimoire.com
|
|
||||||
diun.enable: "true"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Important:** API keys go directly in the `environment:` block (not `env_file:`) because Docker Swarm's `env_file` is only read at deploy time from the deploying machine — not by the container at runtime.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## API Keys
|
|
||||||
|
|
||||||
| Variable | Source | Where to Generate |
|
|
||||||
|----------|--------|-------------------|
|
|
||||||
| `HOMEPAGE_VAR_MAILCOW_KEY` | Mailcow | Admin UI → API |
|
|
||||||
| `HOMEPAGE_VAR_DNS_TOKEN` | Technitium | Administration → API Tokens |
|
|
||||||
| `HOMEPAGE_VAR_OPNSENSE_USER` | OPNsense API key | System → Access → Users → edit user → API Keys |
|
|
||||||
| `HOMEPAGE_VAR_OPNSENSE_PASS` | OPNsense API secret | Same as above (one-time download) |
|
|
||||||
| `HOMEPAGE_VAR_IMMICH_KEY` | Immich | User Settings → API Keys |
|
|
||||||
|
|
||||||
**OPNsense note:** The widget uses API key/secret pairs, not admin credentials. Create a dedicated `homepage` user with Audit group membership and generate an API key on that user.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## settings.yaml — Group Layout
|
|
||||||
|
|
||||||
All groups must be registered in `settings.yaml` with `style: column`. Any group discovered via Docker labels that is **not** listed here will default to full-width (stretching across all columns).
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
layout:
|
|
||||||
Glance:
|
|
||||||
tab: Glance
|
|
||||||
header: false
|
|
||||||
Applications:
|
|
||||||
tab: Netgrimoire
|
|
||||||
style: column
|
|
||||||
Gremlin:
|
|
||||||
tab: Netgrimoire
|
|
||||||
style: column
|
|
||||||
# ... all groups must be listed
|
|
||||||
```
|
|
||||||
|
|
||||||
**Rule:** Whenever you add a new `homepage.group=Something` label to a Swarm service, add a matching entry to `settings.yaml`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## widgets.yaml — Global Info Bar
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- logo:
|
|
||||||
icon: /images/gremlin-badge.png
|
|
||||||
|
|
||||||
- greeting:
|
|
||||||
text_size: xl
|
|
||||||
text: "NetGrimoire"
|
|
||||||
|
|
||||||
- datetime:
|
|
||||||
text_size: l
|
|
||||||
format:
|
|
||||||
dateStyle: long
|
|
||||||
timeStyle: short
|
|
||||||
hour12: true
|
|
||||||
|
|
||||||
- resources:
|
|
||||||
label: ZNAS
|
|
||||||
cpu: true
|
|
||||||
memory: true
|
|
||||||
disk: /
|
|
||||||
uptime: true
|
|
||||||
refresh: 5000
|
|
||||||
|
|
||||||
- resources:
|
|
||||||
label: Hermes
|
|
||||||
cpu: true
|
|
||||||
memory: true
|
|
||||||
cputemp: true
|
|
||||||
uptime: true
|
|
||||||
refresh: 5000
|
|
||||||
|
|
||||||
- resources:
|
|
||||||
label: Docker5
|
|
||||||
cpu: true
|
|
||||||
memory: true
|
|
||||||
uptime: true
|
|
||||||
refresh: 5000
|
|
||||||
|
|
||||||
- openmeteo:
|
|
||||||
label: Pensacola
|
|
||||||
latitude: 30.42
|
|
||||||
longitude: -87.21
|
|
||||||
units: imperial
|
|
||||||
cache: 5
|
|
||||||
|
|
||||||
- search:
|
|
||||||
provider: duckduckgo
|
|
||||||
target: _blank
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note:** Resource widgets currently show stats for the Homepage host only. Deploy the Homepage agent on each node for true per-node metrics.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Branding — Gremlin Images
|
|
||||||
|
|
||||||
| File | Usage |
|
|
||||||
|------|-------|
|
|
||||||
| `/DockerVol/homepage/images/gremlin-badge.png` | Logo widget (circular badge) |
|
|
||||||
| `/DockerVol/homepage/images/gremlin-scene.png` | Gremlin AI service card background |
|
|
||||||
|
|
||||||
After adding new images, restart the Homepage container — Next.js static server does not pick up new files without a restart.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Service Widgets
|
|
||||||
|
|
||||||
| Service | Widget Type | URL |
|
|
||||||
|---------|-------------|-----|
|
|
||||||
| Mailcow | `customapi` | `http://192.168.5.16/api/v1/get/domain/all` |
|
|
||||||
| Technitium | `customapi` | `http://192.168.5.7:5380/api/dashboard/stats/get` |
|
|
||||||
| OPNsense | `opnsense` | `https://192.168.3.4:8443` |
|
|
||||||
| Immich | `immich` | `https://immich.netgrimoire.com` |
|
|
||||||
| Jackett | `jackett` | `http://gluetun:9117` |
|
|
||||||
| Radarr | `radarr` | `http://radarr:7878` |
|
|
||||||
| Sonarr | `sonarr` | `http://sonarr:8989` |
|
|
||||||
| SABnzbd | `sabnzbd` | `http://sabnzbd:8080` |
|
|
||||||
|
|
||||||
**Mailcow widget note:** The native `mailcow` widget type is broken with Mailcow 2025+ (API endpoint `/api/v1/get/mailboxes` was removed). Use `customapi` pointing at `/api/v1/get/domain/all` instead.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## custom.css — Key Sections
|
|
||||||
|
|
||||||
The CSS uses a Netgrimoire dark ops aesthetic with per-tab color theming:
|
|
||||||
|
|
||||||
| Tab | Accent Color |
|
|
||||||
|-----|-------------|
|
|
||||||
| Netgrimoire | Teal (`#00e5cc`) |
|
|
||||||
| Wasted-Bandwidth | Amber (`#ffaa00`) |
|
|
||||||
| Nucking-Futz | Red (`#ff4455`) |
|
|
||||||
| PNCHarris | Teal (narrow column layout) |
|
|
||||||
|
|
||||||
**Critical fix:** `html, body, body > div { background-color: transparent !important; }` must be present or Homepage's root div paints over the body background, hiding tab background images.
|
|
||||||
|
|
||||||
**Card layout:** Groups use `style: column` in settings.yaml. The CSS does not override the grid — Homepage's own Tailwind layout handles column placement.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
| Problem | Cause | Fix |
|
|
||||||
|---------|-------|-----|
|
|
||||||
| Card stretches full width | Group not in settings.yaml | Add group with `style: column` |
|
|
||||||
| Background image not showing | Missing transparent fix in CSS | Add `html, body, body > div { background-color: transparent !important }` |
|
|
||||||
| Widget shows API error | Wrong URL or missing API key | Check env vars and use internal container URLs |
|
|
||||||
| Logo not showing | Image not in `/app/public/images` | Copy to `/DockerVol/homepage/images/` and restart container |
|
|
||||||
| New image not loading | Next.js static cache | Restart the Homepage container after adding images |
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue