This commit is contained in:
2026-04-03 10:44:26 +02:00
commit 736477cf57
19 changed files with 622 additions and 0 deletions

32
docs/adguard.md Normal file
View File

@@ -0,0 +1,32 @@
# AdGuard Home
**Purpose:** Network-wide DNS-based ad and tracker blocking.
| Property | Value |
| -------------- | ------------------------------ |
| Status | Running |
| Image | `adguard/adguardhome:latest` |
| Ports | `53:53/tcp`, `53:53/udp` (DNS) |
| Created by | jens |
| Restart policy | `unless-stopped` |
| Web UI | <https://adguard.home.jens.pub> |
| Compose file | [`../services/adguard/docker-compose.yml`](../services/adguard/docker-compose.yml) |
---
## Configuration
- Exposed as DNS server on port 53 (TCP + UDP)
- Web UI proxied through Traefik at `adguard.home.jens.pub`
- Traefik routes to container port 80 (AdGuard's HTTP UI)
## Volumes
| Volume | Mount |
| -------------- | --------------------------------------- |
| `adguard_work` | `/opt/adguardhome/work` — working data |
| `adguard_conf` | `/opt/adguardhome/conf` — configuration |
## Networks
- `proxy` (external)

48
docs/beszel.md Normal file
View File

@@ -0,0 +1,48 @@
# Beszel
**Purpose:** Lightweight container and host metrics monitoring (CPU, memory, disk, network).
| Property | Value |
| -------------- | ------------------------------ |
| Status | Running |
| Hub image | `henrygd/beszel:latest` |
| Agent image | `henrygd/beszel-agent:latest` |
| Web UI | <https://beszel.home.jens.pub> |
| Compose file | [`../services/beszel/docker-compose.yml`](../services/beszel/docker-compose.yml) |
---
## Architecture
Beszel uses a **hub + agent** model:
- **Hub** — web UI and data store, proxied via Traefik at `beszel.home.jens.pub`
- **Agent** — runs in host network mode, collects metrics and communicates with the hub via a shared Unix socket (`/beszel_socket/beszel.sock`)
## Setup
On first run, open `beszel.home.jens.pub`, create an admin account, then add the local system:
1. Go to **Systems → Add system**
2. Set host to the Unix socket path: `/beszel_socket/beszel.sock`
3. Copy the generated public key
4. Set `BESZEL_KEY` in Portainer's stack env vars and redeploy
## Environment Variables
| Variable | Description | Source |
| ------------- | ---------------------------------- | ------ |
| `APP_URL` | `https://beszel.home.jens.pub` | hardcoded |
| `LISTEN` | `/beszel_socket/beszel.sock` | hardcoded |
| `BESZEL_KEY` | Hub public key for agent auth | `.env` |
## Volumes
| Volume | Mount |
| ---------------- | ------------------- |
| `beszel_data` | `/beszel_data` — hub database and config |
| `beszel_socket` | `/beszel_socket` — shared Unix socket between hub and agent |
| `/var/run/docker.sock` | `:ro` — Docker socket for container metrics (agent) |
## Networks
- Hub: `proxy` (external)
- Agent: `host`

28
docs/dozzle.md Normal file
View File

@@ -0,0 +1,28 @@
# Dozzle
**Purpose:** Real-time Docker container log viewer.
| Property | Value |
| -------------- | --------------------------- |
| Status | Running |
| Image | `amir20/dozzle:latest` |
| Web UI | <https://logs.home.jens.pub> |
| Compose file | [`../services/dozzle/docker-compose.yml`](../services/dozzle/docker-compose.yml) |
---
## Configuration
- Live log streaming for all containers
- No credentials required by default — consider enabling auth if exposed publicly
## Volumes
| Volume | Mount |
| ------------- | ------------------------------------------- |
| `dozzle_data` | `/data` — notification settings and config |
| `/var/run/docker.sock` | `:ro` — Docker socket for log access |
## Networks
- `proxy` (external)

123
docs/index.md Normal file
View File

@@ -0,0 +1,123 @@
# Portainer — Homelab Documentation
> Generated: 2026-04-02
> Source: <https://portainer.home.jens.pub>
---
## Instance Overview
| Property | Value |
| -------------- | --------------------------------- |
| Edition | Portainer EE (Enterprise Edition) |
| Image | `portainer/portainer-ee:lts` |
| URL | <https://portainer.home.jens.pub> |
| Container port | 9443 (HTTPS) |
| Uptime | Running |
---
## Portainer Settings
| Setting | Value |
| ----------------------- | ---------------------------- |
| Authentication | Internal (username/password) |
| Minimum password length | 12 characters |
| User session timeout | 8 hours |
| Snapshot interval | 5 minutes |
| Edge compute | Disabled |
| OAuth / LDAP | Not configured |
### Users
| Username | Role |
| -------- | ------------- |
| `jens` | Administrator |
---
## Environment (Endpoint)
Single environment: **local**
| Property | Value |
| ------------------ | ----------------------------- |
| Type | Docker standalone |
| Connection | `unix:///var/run/docker.sock` |
| Docker version | 29.3.0 |
| CPUs | 6 |
| Memory | ~15.5 GB |
| Running containers | 3 |
| Volumes | 4 |
| Images | 7 |
| Stacks | 2 (traefik, adguard) |
| Swarm | No |
### Security Settings
- Bind mounts for regular users: **disabled**
- Privileged mode for regular users: **disabled**
- Host namespace for regular users: **disabled**
- Stack management for regular users: **allowed**
---
## Docker Networks
| Name | Driver | Scope | Notes |
| -------- | ------ | ----- | --------------------------------- |
| `proxy` | bridge | local | Shared network used by all stacks |
| `bridge` | bridge | local | Docker default |
| `host` | host | local | Docker default |
| `none` | null | local | Docker default |
The `proxy` network is an **external** bridge network created manually. All services that need Traefik routing must be attached to it.
---
## Running Stacks
| Stack | Purpose | Docs |
| ---------- | ------------------------------ | ------------------------ |
| `traefik` | Reverse proxy + TLS | [traefik.md](traefik.md) |
| `adguard` | DNS ad/tracker blocking | [adguard.md](adguard.md) |
| `portainer` | Container management UI | [portainer.md](portainer.md) |
| `vaultwarden` | Password manager | [vaultwarden.md](vaultwarden.md) |
| `watchtower` | Automatic image updates | [watchtower.md](watchtower.md) |
| `beszel` | Container & host metrics | [beszel.md](beszel.md) |
| `dozzle` | Container log viewer | [dozzle.md](dozzle.md) |
---
## Service Map
```
Internet
[Host :80/:443]
[traefik:v3.6] ──── TLS wildcard cert (*.home.jens.pub via Namecheap DNS-01)
├── traefik.home.jens.pub ──→ Traefik dashboard (api@internal)
├── adguard.home.jens.pub ──→ adguard:80 (AdGuard web UI)
├── portainer.home.jens.pub ──→ portainer:9000
├── vault.home.jens.pub ──→ vaultwarden:80 (password manager)
├── beszel.home.jens.pub ──→ beszel:8090 (metrics)
└── logs.home.jens.pub ──→ dozzle:8080 (log viewer)
[adguard/adguardhome] ──── DNS :53 (TCP/UDP)
[portainer/portainer-ee] ──── Portainer UI :9443
All services share the external `proxy` bridge network.
```
---
## Notes & Considerations
- **Sensitive credentials in stack definitions:** The `traefik` stack has the Namecheap API key and source IP hardcoded in the compose environment. Consider moving these to a `.env` file or Portainer's secret/environment variable management.
- **AdGuard image tag:** Using `latest` — consider pinning to a specific version for reproducibility.
- **Portainer not in a stack:** The Portainer container itself is not managed as a Portainer stack (typical self-managed setup).
- **Access control:** The `traefik` stack is admin-only. The `adguard` stack grants explicit access to user `jens` (ID 1).

32
docs/portainer.md Normal file
View File

@@ -0,0 +1,32 @@
# Portainer (service)
**Purpose:** Docker container management UI.
| Property | Value |
| -------------- | --------------------------------- |
| Status | Running |
| Image | `portainer/portainer-ee:lts` |
| Ports | `9443:9443` (HTTPS, direct) |
| Restart policy | `unless-stopped` |
| Web UI | <https://portainer.home.jens.pub> |
| Compose file | [`../services/portainer/docker-compose.yml`](../services/portainer/docker-compose.yml) |
---
## Configuration
- Port 9443 published directly to the host for HTTPS access
- Port 9000 (HTTP) used internally — Traefik proxies `portainer.home.jens.pub` to it
- Port 8000 (Edge agent tunnel) not exposed
- Not managed as a Portainer stack — deployed manually from `/home/jens/portainer/`
## Volumes
| Volume | Mount |
| ---------------- | ------- |
| `portainer_data` | `/data` |
| `/var/run/docker.sock` | `:rw` — Docker socket for container management |
## Networks
- `proxy` (external)

43
docs/traefik.md Normal file
View File

@@ -0,0 +1,43 @@
# Traefik
**Purpose:** Reverse proxy and TLS termination for all homelab services.
| Property | Value |
| -------------- | ------------------ |
| Status | Running |
| Image | `traefik:v3.6` |
| Ports | `80:80`, `443:443` |
| Created by | jens |
| Restart policy | `unless-stopped` |
| Compose file | [`../services/traefik/docker-compose.yml`](../services/traefik/docker-compose.yml) |
---
## Configuration
- HTTP (port 80) → automatically redirects to HTTPS
- HTTPS (port 443) → TLS termination via Let's Encrypt
- TLS wildcard certificate for `*.home.jens.pub` and `home.jens.pub`
- Certificate resolver: **Let's Encrypt** via **DNS-01 challenge** (Namecheap provider)
- DNS resolvers used for challenge: `1.1.1.1`, `8.8.8.8`
- Docker provider: auto-discovers containers via socket (opt-in with `traefik.enable=true`)
- Dashboard: enabled, exposed at `traefik.home.jens.pub` (secured, no insecure mode)
## Environment Variables (sensitive)
| Variable | Description |
| --------------------- | --------------------------------------- |
| `NAMECHEAP_API_USER` | Namecheap account username |
| `NAMECHEAP_API_KEY` | Namecheap API key for DNS challenge |
| `NAMECHEAP_SOURCE_IP` | Whitelisted IP for Namecheap API access |
## Volumes
| Volume | Mount |
| ---------------------- | ------------------------------------------- |
| `/var/run/docker.sock` | `:ro` — Docker socket for service discovery |
| `traefik_acme` | `/acme` — Let's Encrypt certificate storage |
## Networks
- `proxy` (external)

45
docs/vaultwarden.md Normal file
View File

@@ -0,0 +1,45 @@
# Vaultwarden
**Purpose:** Self-hosted password manager (Bitwarden-compatible server).
| Property | Value |
| -------------- | -------------------------------- |
| Status | Deployed (env vars pending) |
| Image | `vaultwarden/server:latest` |
| Ports | None (Traefik only) |
| Restart policy | `unless-stopped` |
| Web UI | <https://vault.home.jens.pub> |
| Admin UI | <https://vault.home.jens.pub/admin> |
| Compose file | [`../services/vaultwarden/docker-compose.yml`](../services/vaultwarden/docker-compose.yml) |
---
## Configuration
- Web UI and API proxied through Traefik at `vault.home.jens.pub`
- Traefik routes to container port 80
- Admin panel available at `/admin` (requires `ADMIN_TOKEN`)
## Environment Variables
| Variable | Description | Source |
| --------------- | ------------------------------------ | -------- |
| `ADMIN_TOKEN` | Token to access the `/admin` UI | `.env` |
| `SMTP_HOST` | `smtp.mailbox.org` | hardcoded |
| `SMTP_PORT` | `587` | hardcoded |
| `SMTP_SECURITY` | `starttls` | hardcoded |
| `SMTP_FROM` | `mail@jens.pub` | hardcoded |
| `SMTP_USERNAME` | `mail@jens.pub` | hardcoded |
| `SMTP_PASSWORD` | mailbox.org account password | `.env` |
> `ADMIN_TOKEN` and `SMTP_PASSWORD` must be set in Portainer's stack env vars before starting the container.
## Volumes
| Volume | Mount |
| ----------------- | ------- |
| `vaultwarden_data` | `/data` — database, attachments, config |
## Networks
- `proxy` (external)

54
docs/watchtower.md Normal file
View File

@@ -0,0 +1,54 @@
# Watchtower
**Purpose:** Automatically updates Docker container images on a schedule and sends email notifications.
| Property | Value |
| -------------- | ------------------------------ |
| Status | Running |
| Image | `nickfedor/watchtower:latest` |
| Ports | None |
| Restart policy | `unless-stopped` |
| Schedule | Daily at 03:00 |
| Compose file | [`../services/watchtower/docker-compose.yml`](../services/watchtower/docker-compose.yml) |
---
## Configuration
- Checks for updated images daily at 03:00 (`0 0 3 * * *`)
- Automatically pulls and restarts containers with updated images
- Removes old images after updating (`WATCHTOWER_CLEANUP=true`)
- Sends an email summary to `mail@jens.pub` after each run
## Environment Variables
| Variable | Value | Source |
| ------------------------------------------- | ---------------------- | --------- |
| `WATCHTOWER_SCHEDULE` | `0 0 3 * * *` | hardcoded |
| `WATCHTOWER_CLEANUP` | `true` | hardcoded |
| `WATCHTOWER_NOTIFICATIONS` | `email` | hardcoded |
| `WATCHTOWER_NOTIFICATION_EMAIL_FROM` | `mail@jens.pub` | hardcoded |
| `WATCHTOWER_NOTIFICATION_EMAIL_TO` | `mail@jens.pub` | hardcoded |
| `WATCHTOWER_NOTIFICATION_EMAIL_SERVER` | `smtp.mailbox.org` | hardcoded |
| `WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT` | `587` | hardcoded |
| `WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER` | `mail@jens.pub` | hardcoded |
| `WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD` | mailbox.org password | `.env` |
## Excluding Containers
To exclude a container from being updated by Watchtower, add this label to it:
```yaml
labels:
- "com.centurylinklabs.watchtower.enable=false"
```
## Volumes
| Volume | Mount |
| ---------------------- | ------------------------------------------- |
| `/var/run/docker.sock` | `:ro` — Docker socket for container monitoring |
## Networks
- `proxy` (external)