Compare commits

...

166 Commits

Author SHA1 Message Date
274f947279 fix: remove intel config 2026-02-08 15:02:11 +00:00
4e9fa05dd4 fix: remove traefik 2026-02-08 14:58:14 +00:00
f33aabd9ae feat: fix for intel igpu 2026-02-08 14:36:57 +00:00
0a4c4b4d03 fix: drivers 2026-02-08 13:43:44 +00:00
4600b89d3e feat: increase shared memory 2026-02-08 13:34:12 +00:00
94f09bd3ce feat: add frigate 2026-02-08 12:47:17 +00:00
144f5678f7 fix: config path 2026-02-01 01:46:16 +00:00
6b3719db95 feat: add jellysweep 2026-02-01 01:35:09 +00:00
b6288e6fc9 fix: use correct protocol 2026-01-28 03:48:09 +00:00
fc01e3b5c7 fix: http rather than tcp 2026-01-28 03:45:41 +00:00
021cef6e25 feat: use address for routing 2026-01-28 03:41:15 +00:00
27b5d20b49 feat: put adguard on traefik_public 2026-01-28 03:32:46 +00:00
3fea6e5432 feat: Add Spoolman service for 3D printing management 2026-01-26 20:10:14 +00:00
b169c0beb7 feat(media): add jellystat service 2026-01-20 20:49:16 +00:00
9faa1b4f6d feat: add middleware to adguard 2026-01-18 16:45:13 +00:00
9ce0bfaf70 feat: remove nzbget from gluetun 2026-01-18 16:15:59 +00:00
f3dddbd21f feat: conf 2026-01-18 16:13:26 +00:00
14aad65e0f feat: conf gluetun 2026-01-18 16:11:34 +00:00
6516f8472d feat: use local dns 2026-01-18 15:57:36 +00:00
1a31ff6708 feat: whitelist traefik subnet 2026-01-18 15:49:34 +00:00
2a90e09607 feat: back to wireguard 2026-01-15 00:25:41 +00:00
6ad6c47883 fix: try google dns 2026-01-15 00:12:53 +00:00
02e12d6a63 feat: use protons dns 2026-01-15 00:10:34 +00:00
44c8bf74a2 fix: wrong env var 2026-01-15 00:03:47 +00:00
e13167f098 feat: switch to openvpn 2026-01-15 00:00:36 +00:00
531fb2cdc1 feat: add audiobookshelf 2026-01-10 20:51:16 +00:00
de1df5375b fix: docker compose 2026-01-10 20:04:42 +00:00
0ce7315e11 fix: gluetun 2026-01-09 20:05:20 +00:00
1fa30ad70c fix: derp 2026-01-06 20:05:05 +00:00
888aa91da8 fix: add default traefik network label 2026-01-06 19:58:50 +00:00
9be0f377ad feat: add habitica 2026-01-06 19:48:53 +00:00
991bd9be31 feat: remove plex 2026-01-06 18:51:47 +00:00
a874027a00 feat: remove nginx proxy manager 2026-01-06 18:50:56 +00:00
5d2214b612 feat: remove duckdns 2026-01-06 18:50:33 +00:00
4f80f77313 feat: remove hypermind 2026-01-06 18:50:17 +00:00
f492d7f41a feat: remove homepage 2026-01-06 18:49:23 +00:00
e16e838a12 feat: remove portainer 2026-01-06 18:48:47 +00:00
523a2ecb13 feat: add voidauth to arr 2026-01-06 12:16:32 +00:00
2805aeaea3 why tho 2026-01-06 01:16:01 +00:00
fb5b281a2b feat: correct network 2026-01-06 01:13:08 +00:00
98517b8dc0 fix: network wrong 2026-01-06 01:10:55 +00:00
6e6ef1a477 fix: remove host mode 2026-01-06 01:09:50 +00:00
c74b60a329 fix: move compose 2026-01-06 01:09:05 +00:00
f64c449460 feat: add the hive mind 2026-01-06 01:07:28 +00:00
ed7b96a024 feat: remove authentik from traefik 2026-01-05 23:39:47 +00:00
4ef86b5c1c fix: traefik label 2026-01-05 23:37:52 +00:00
53d963d2c4 fix: inject env 2026-01-05 23:35:05 +00:00
94fd57e1e6 feat: issue with db path 2026-01-05 23:33:04 +00:00
c7bb480826 fix: traefik labels 2026-01-05 23:27:33 +00:00
74ea269c3d feat: add labels 2026-01-05 23:21:35 +00:00
4b350f47f2 feat: add void 2026-01-05 23:14:46 +00:00
2e159c285b feat: add komodo 2026-01-05 23:08:54 +00:00
a6da94951d feat: glance 2026-01-05 23:08:32 +00:00
610b00531b feat: add glance 2026-01-05 21:33:49 +00:00
3b7e2974fe feat: testing gitops 2026-01-04 23:22:27 +00:00
c4253a2efd feat: test gitops 2026-01-04 23:04:37 +00:00
160e0781b7 fix: tweak adguaerd variables 2026-01-04 21:51:39 +00:00
d1b6c17bac feat: add plex claim 2026-01-01 15:35:04 +00:00
694b77bea5 feat: add plex 2026-01-01 15:07:46 +00:00
6a09720f6e fix: traefik network 2025-12-31 10:32:55 +00:00
487375901f feat(booklore): add traefik and homepage labels 2025-12-31 10:17:27 +00:00
dcfd7f1c7f feat: don't define user 2025-12-31 09:31:50 +00:00
9ed11af52a feat: add booklore 2025-12-31 08:59:49 +00:00
3f132a9169 feat: add new vpn countries 2025-12-30 21:14:40 +00:00
d0def2e259 fix: allow file rotation 2025-12-30 17:20:36 +00:00
51b2edf92b fix: wrong network 2025-12-30 16:54:49 +00:00
0abcc6dcf4 feat: add paperless 2025-12-30 16:33:48 +00:00
1716238835 feat: add mealie 2025-12-29 11:50:28 +00:00
a33d883580 feat: set sched 2025-12-24 19:04:45 +00:00
fc51e15cac fix: incorrect port 2025-12-24 17:20:19 +00:00
2867b43a9c fix: put compose in correct folder 2025-12-24 17:17:05 +00:00
e74211030e feat: add speedtest docker labels 2025-12-24 17:14:37 +00:00
667b01e62f feat: add speedtest-tracker container 2025-12-24 17:10:04 +00:00
cc615cc885 fix: app config for jellyseerr 2025-12-21 17:24:40 +00:00
69ac3adea8 feat: enable hardware encoding 2025-12-21 01:46:44 +00:00
ed79177458 fix: typo 2025-12-21 01:00:20 +00:00
436ac40977 fix: add nextauth url 2025-12-21 00:49:27 +00:00
24978964a1 feat: add oauth to karakeep 2025-12-21 00:44:45 +00:00
6a7b88543e feat: add openai integration to karakeep 2025-12-20 02:18:55 +00:00
74054f33fd feat: meal key inject 2025-12-20 02:12:16 +00:00
1431f2c1ca feat: define secret 2025-12-20 02:06:36 +00:00
5e2c1eec63 fix: bad data dir 2025-12-20 02:03:00 +00:00
ad8e8d6cd7 fix: syntax 2025-12-20 01:59:59 +00:00
ac812e47d2 fix: tweak karakeep compose 2025-12-20 01:58:51 +00:00
fc569046b7 fix: issue with internal networks on karakeep 2025-12-20 01:49:03 +00:00
43fb33511e fix: adjustments 2025-12-20 01:40:49 +00:00
31c8fc8b42 feat: try latest image for search 2025-12-20 01:29:50 +00:00
096ffd851b feat: add karakeep 2025-12-20 01:23:56 +00:00
4d643bea1a feat: add agents md 2025-12-20 01:17:57 +00:00
8d7b353cc2 feat: agent config 2025-12-20 00:05:39 +00:00
ad6bff89cb feat: add beszel 2025-12-19 23:58:31 +00:00
72b13f80fb feat: add homepage labels to traefik 2025-12-19 23:53:53 +00:00
773149e931 feat: new syntax 2025-12-19 23:32:19 +00:00
adbd765e72 feat: try priority 2025-12-19 23:26:15 +00:00
d075f470cd feat: outpost rule (again) 2025-12-19 23:20:26 +00:00
ece646d07a feat: more authentik stuff 2025-12-19 23:14:09 +00:00
5503c2c6f4 feat remove authentik stuff 2025-12-19 23:06:47 +00:00
82ed5a3fb0 feat: remove traefik stuff 2025-12-19 23:05:26 +00:00
0c901180d9 fix: outpost router 2025-12-19 22:44:12 +00:00
126a0f1f89 feat: traefik auth flow 2025-12-19 22:44:12 +00:00
07616ed43d fix: correct version on auth worker 2025-12-19 18:49:15 +00:00
60a6cb238c fix: unpin authentik 2025-12-19 18:20:47 +00:00
4d40d3facb feat: try to fix traefik issue 2025-12-19 17:32:34 +00:00
36da7e45a3 fix: postgres retry 2025-12-19 17:19:02 +00:00
e1a5cc1212 fix: redis healthcheck 2025-12-19 17:18:31 +00:00
b8ad84cba5 feat: authentik 2025-12-19 17:11:51 +00:00
38a642ce6d feat: remove recommendarr 2025-12-19 15:41:40 +00:00
0baf5c3791 fix: don't route recommendarr through gluetun 2025-12-19 15:35:12 +00:00
4b2138fac3 feat: add traefik and homepage labels for recommendarr 2025-12-19 15:26:39 +00:00
99392d66d9 fix: correct recommendarr image 2025-12-19 15:23:23 +00:00
a57c65f9ea feat: add recomendarr 2025-12-19 15:21:29 +00:00
b0cdfbac5d feat: add nzbget 2025-12-19 14:25:42 +00:00
07c87314f0 feat: add arrstack 2025-12-19 13:42:35 +00:00
510a132268 feat: clean up redundant networks 2025-12-19 00:11:28 +00:00
2d021505a3 chore: rename kuma container 2025-12-18 23:56:11 +00:00
a665d9b88a fix: typo 2025-12-18 22:34:34 +00:00
fbbedaae3c feat: network configure 2025-12-18 22:32:31 +00:00
7e0cb3d0e2 feat: final 2025-12-18 21:02:56 +00:00
c9652dd29d fix: maybe? 2025-12-18 21:00:00 +00:00
45287a7e54 fix: try https 2025-12-18 20:53:28 +00:00
5488e14ec7 fix: properly 2025-12-18 20:50:53 +00:00
a435cb72dc feat: remove traefik_docker network 2025-12-18 20:50:26 +00:00
904eb67094 feat: refert to the old way 2025-12-18 20:47:12 +00:00
ba4c2c55ef fix: adjust media and proxy 2025-12-18 20:41:33 +00:00
70c4311c91 feat: traefik proxy network 2025-12-18 20:23:47 +00:00
cdf9cfeaa6 fix: image names 2025-12-18 20:21:02 +00:00
77abf0af2b fix: image name for jellystat 2025-12-18 20:16:51 +00:00
0eebc10f1e feat: add jellyfin stack 2025-12-18 20:10:35 +00:00
05b0eeaecb fix: correct widget url 2025-12-18 10:16:25 +00:00
96d77f19fb fix: incorrect widget type 2025-12-18 10:15:23 +00:00
73f3c2ede3 feat: kuma widget 2025-12-18 10:14:21 +00:00
195478d5bd feat: mount docker socket on uptime kuma 2025-12-18 09:46:08 +00:00
fe34ff9446 feat: add uptime-kuma 2025-12-17 23:13:09 +00:00
9233cc5ba3 feat: add glances in correct folder 2025-12-17 23:01:38 +00:00
39f9930ec1 fix: icon for zerobyte 2025-12-17 22:24:08 +00:00
aec7a626a2 feat: fix traefik labels 2025-12-17 21:42:46 +00:00
80bf226fb7 fix: sort rclone 2025-12-17 21:29:11 +00:00
3baeeb0b0a feat: annotate container 2025-12-17 21:20:50 +00:00
80bf5047ac fix: erronious plus sign 2025-12-17 21:17:38 +00:00
64a46f01f3 feat: add zerobyte 2025-12-17 21:03:29 +00:00
f44f94d239 feat: add cloudflared 2025-12-17 16:54:31 +00:00
005cbc4224 feat: add duckdns 2025-12-16 20:42:16 +00:00
64693b325c fix: correct port for adguard reverse proxy 2025-12-16 19:41:07 +00:00
b21bd6370d feat: fix insecure transport 2025-12-16 13:52:16 +00:00
be7ebc1725 feat: gittea changes 2025-12-16 13:43:17 +00:00
0ecf24db47 feat: add adguard traefik config 2025-12-16 13:40:05 +00:00
10753c0be6 feat: add homepage traefik 2025-12-16 13:37:09 +00:00
57eb29cac2 feat: portainer traefik 2025-12-16 13:36:35 +00:00
38eb5a989c feat: add traefik container 2025-12-16 13:20:36 +00:00
9bc8b0436e fix: broken core keeper icon 2025-12-16 01:26:50 +00:00
9be80261c6 feat: add homepage config 2025-12-16 00:37:01 +00:00
edf6a9cd98 feat: update readme 2025-12-16 00:25:23 +00:00
2afdcec453 feat: use CONFIG_ROOT for core keeper 2025-12-16 00:14:40 +00:00
c2ad2dcb03 feat: add config root to adguard 2025-12-16 00:04:24 +00:00
ab63aae3f9 feat: move data for npm 2025-12-15 23:56:39 +00:00
432727f16b feat: use config root for gittea 2025-12-15 23:48:55 +00:00
a691641e4d feat: use adguard in host mode 2025-12-15 22:50:15 +00:00
7e834f2bce feat: expose dhcp ports on adguard 2025-12-15 22:36:40 +00:00
fa69b4f1ad fix: dns stub issue 2025-12-15 22:32:49 +00:00
d7c0c535e1 feat: add gittea 2025-12-15 22:22:27 +00:00
47416e7a82 feat: add adguard 2025-12-15 22:21:27 +00:00
42868a991e feat: remove coredns 2025-12-15 22:20:07 +00:00
db35dda87c feat: add coredns 2025-12-15 22:09:24 +00:00
eebec67179 feat: add core keeper 2025-12-15 21:33:30 +00:00
bdcd970cc6 feat: add ignore for env 2025-12-15 21:21:37 +00:00
799ce67685 feat: updated gitignore 2025-12-15 21:16:50 +00:00
37 changed files with 1489 additions and 47 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
volumes/
.env

View File

@@ -0,0 +1,30 @@
services:
spoolman:
container_name: spoolman
image: ghcr.io/donkie/spoolman:latest
restart: unless-stopped
volumes:
- ${CONFIG_ROOT}/spoolman:/home/app/.local/share/spoolman
labels:
homepage.group: "3D Printing"
homepage.name: "Spoolman"
homepage.icon: "spoolman.png"
homepage.href: "https://spoolman.${DOMAIN}"
homepage.description: "Filament Inventory Manager"
traefik.enable: "true"
traefik.http.routers.spoolman.rule: "Host(`spoolman.${DOMAIN}`)"
traefik.http.routers.spoolman.entrypoints: "https"
traefik.http.routers.spoolman.tls.certresolver: "cloudflare"
traefik.http.routers.spoolman.service: "spoolman"
traefik.http.routers.spoolman.middlewares: "voidauth@docker"
traefik.http.services.spoolman.loadbalancer.server.port: "8000"
environment:
- TZ=Europe/London
- PUID=1000
- PGID=1000
networks:
- traefik_public
networks:
traefik_public:
external: true

75
AGENTS.md Normal file
View File

@@ -0,0 +1,75 @@
# Repository Architecture & Deployment Guide
This document outlines the structure and deployment strategy for the Kendrick Homelab repository. It is intended to guide AI agents and developers in understanding the system's organization.
## 1. Overview
This repository serves as the "Infrastructure as Code" (IaC) source for a self-hosted homelab. It is designed to be consumed by **Portainer** using its Git integration feature (Stacks).
- **Primary Goal:** specific, modular deployment of Docker services.
- **Deployment Method:** Portainer Stacks (Git Repository).
- **Orchestration:** Docker Compose.
## 2. Directory Structure
The repository follows a strict **Category > Service > Configuration** hierarchy. This ensures that every service is self-contained and easily locatable.
```text
/
├── category_name/ # e.g., "access_management", "media"
│ └── service_name/ # e.g., "authentik", "jellyfin"
│ ├── docker-compose.yml # The service definition
│ └── .env.example # (Optional) Template for environment variables
├── backups/ # Backup configurations
├── dashboards/ # Dashboard services (e.g., Homepage)
└── monitoring/ # System monitoring stack
```
### Naming Conventions
- **Categories:** Lowercase, snake_case (e.g., `access_management`).
- **Services:** Lowercase, hyphen-separated if needed (e.g., `core-keeper`).
- **Files:** Strictly `docker-compose.yml` for Portainer compatibility.
## 3. Deployment Strategy (Portainer)
Each subdirectory containing a `docker-compose.yml` is intended to be deployed as a separate **Stack** in Portainer.
- **Repository URL:** This git repository.
- **Compose Path:** Relative path to the file (e.g., `proxies/traefik/docker-compose.yml`).
- **Environment Variables:** injected via the Portainer UI ("Environment variables" section) for each stack. Do not hardcode secrets in Git.
- **Security:** Never include actual secrets (API keys, passwords) in `docker-compose.yml`. Use environment variable placeholders (e.g., `${API_KEY}`).
## 4. Common Patterns & Configuration
### Networking
- **External Network:** Most public-facing services connect to a pre-defined external network (typically `traefik_public` or similar) to allow the reverse proxy to route traffic to them.
- **Internal Communication:** Services within the same stack communicate via the default bridge network created by Docker Compose.
### Reverse Proxy (Traefik/NPM)
- **Traefik:** Used as the primary ingress controller. Services use labels (e.g., `traefik.enable=true`) to expose themselves.
- **Nginx Proxy Manager (NPM):** Available as an alternative or secondary proxy in `proxies/npm`.
### Dashboard Integration (Homepage)
- **Discovery:** Services utilize specific Docker labels (e.g., `homepage.group`, `homepage.name`) to automatically register themselves on the central dashboard.
### Environment Variables
Common variables expected across stacks:
- `DOMAIN`: The root domain name (e.g., `example.com`).
- `CONFIG_ROOT`: Path on the host system where persistent configuration is stored.
- `PUID`/`PGID`: User and Group IDs for file permission management.
## 5. Service Inventory
| Category | Services Included |
|----------------------|-------------------|
| **Access Management**| Authentik |
| **Backups** | Zerobyte |
| **Container Mgmt** | Portainer |
| **Dashboards** | Homepage |
| **DNS** | AdGuard Home, DuckDNS |
| **Games** | Core Keeper |
| **Media** | ArrStack (Radarr/Sonarr etc.), Jellyfin, Plex |
| **Monitoring** | Beszel, Glances, Uptime Kuma |
| **Proxies** | Nginx Proxy Manager (NPM), Traefik |
| **Remote Access** | Cloudflared |
| **Version Control** | Gitea |

View File

@@ -0,0 +1,88 @@
```text
__ __ __ _ __ __ __
/ //_/__ ____ ____/ /____(_)____/ /__ / / ____ _/ /_
/ ,< / _ \/ __ \/ __ / ___/ / ___/ //_/ / / / __ `/ __ \
/ /| / __/ / / / /_/ / / / / /__/ ,< / /___/ /_/ / /_/ /
/_/ |_\___/_/ /_/\__,_/_/ /_/\___/_/|_| /_____/\__,_/_.___/
```
================================================================================
WELCOME TO THE LAB.
Where containers live, services thrive, and uptime is (mostly) guaranteed.
================================================================================
This repository houses the Docker Compose configurations for the Kendrick Homelab.
Everything needed to spin up the core infrastructure, management tools, and
entertainment services is right here.
```text
___ __ _ _
|_ _|_ __ / _|_ __ __ _ ___| |_ _ __ _ _ ___| |_ _ _ _ __ ___
| || '_ \| |_| '__/ _` / __| __| '__| | | |/ __| __| | | | '__/ _ \
| || | | | _| | | (_| \__ \ |_| | | |_| | (__| |_| |_| | | | __/
|___|_| |_|_| |_| \__,_|___/\__|_| \__,_|\___|\__|\__,_|_| \___|
```
The backbone of the operation. Without these, nothing talks to anything.
* **DNS / AdBlocker**: `dns/adguard` - AdGuard Home for network-wide ad blocking and DNS management.
* **Reverse Proxy**: `proxies/npm` - Nginx Proxy Manager to handle SSL and route traffic.
* **Remote Access**: `remote_access/cloudflared` - Cloudflare Tunnel for secure remote access.
```text
__ __ _
| \/ | __ _ _ __ __ _ __ _ ___ _ __ ___ ___ _ __ | |_
| |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '_ ` _ \ / _ \ '_ \| __|
| | | | (_| | | | | (_| | (_| | __/ | | | | | __/ | | | |_
|_| |_|\__,_|_| |_|\__,_|\__, |\___|_| |_| |_|\___|_| |_|\__|
|___/
```
Tools to keep the ship sailing smooth.
* **Access Management**: `access_management/authentik` - Identity provider and SSO service (Authentik).
* **Container Management**: `container_management/portainer` - Visual management for Docker.
* **Version Control**: `version_control/gittea` - Self-hosted Git service (Gitea).
```text
_____ _ _ _ _
| ____|_ __ | |_ ___ _ __| |_ __ _(_)_ __ _ __ ___ ___ _ __ | |_
| _| | '_ \| __/ _ \ '__| __/ _` | | '_ \| '_ ` _ \ / _ \ '_ \| __|
| |___| | | | || __/ | | || (_| | | | | | | | | | | __/ | | | |_
|_____|_| |_|\__\___|_| \__\__,_|_|_| |_|_| |_| |_|\___|_| |_|\__|
```
Because all work and no play makes the server a dull boy.
* **Books**: `books/booklore` - eBook management (Booklore).
* **Games**: `games/core-keeper` - Dedicated server for Core Keeper.
* **Media - Jellyfin**: `media/jellyfin` - Jellyfin Media Server.
* **Media - Plex**: `media/plex` - Plex Media Server.
* **Media - ArrStack**: `media/arrstack` - The *Arr stack.
* **3D Printing**: `3d_printing/spoolman` - Filament inventory manager (Spoolman).
### Directory Structure
```
.
├── 3d_printing/
│ └── spoolman/
├── books/
│ └── booklore/
├── container_management/
│ └── portainer/
├── dns/
│ └── adguard/
├── games/
│ └── core-keeper/
├── media/
├── proxies/
│ └── npm/
├── remote_access/
│ └── cloudflared/
├── version_control/
│ └── gittea/
└── volumes/
```
--------------------------------------------------------------------------------
Generated with <3 and figlet.

View File

@@ -0,0 +1,10 @@
# Authentik Configuration
PG_PASS=your_postgres_password
PG_USER=authentik
PG_DB=authentik
AUTHENTIK_SECRET_KEY=your_authentik_secret_key
# Global variables (usually defined in root .env or shell environment)
# DOMAIN=example.com
# CONFIG_ROOT=/path/to/config

View File

@@ -0,0 +1,106 @@
version: "3.8"
services:
postgresql:
image: docker.io/library/postgres:16-alpine
container_name: authentik-postgres
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
start_period: 20s
interval: 30s
timeout: 5s
volumes:
- ${CONFIG_ROOT}/authentik/postgres:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: ${PG_PASS}
POSTGRES_USER: ${PG_USER:-authentik}
POSTGRES_DB: ${PG_DB:-authentik}
networks:
- authentik_internal
redis:
image: docker.io/library/redis:alpine
container_name: authentik-redis
command: --save 60 1 --loglevel warning
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
start_period: 20s
interval: 30s
timeout: 5s
volumes:
- ${CONFIG_ROOT}/authentik/redis:/data
networks:
- authentik_internal
server:
image: ghcr.io/goauthentik/server:latest
container_name: authentik-server
restart: unless-stopped
command: server
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_POSTGRESQL__HOST: postgresql
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
AUTHENTIK_ERROR_REPORTING__ENABLED: "true"
volumes:
- ${CONFIG_ROOT}/authentik/media:/media
- ${CONFIG_ROOT}/authentik/custom-templates:/templates
networks:
- authentik_internal
- traefik_public
labels:
# Traefik
traefik.enable: "true"
traefik.docker.network: "traefik_public"
traefik.http.routers.authentik.rule: "Host(`auth.${DOMAIN}`)"
traefik.http.routers.authentik.entrypoints: "https"
traefik.http.routers.authentik.tls.certresolver: "cloudflare"
# Authentik Outpost Router (prevents redirect loops)
traefik.http.routers.authentik-outpost.rule: "PathPrefix(`/outpost.goauthentik.io/`)"
traefik.http.routers.authentik-outpost.priority: "100"
traefik.http.routers.authentik-outpost.entrypoints: "https"
traefik.http.routers.authentik-outpost.tls.certresolver: "cloudflare"
traefik.http.routers.authentik-outpost.service: "authentik"
traefik.http.services.authentik.loadbalancer.server.port: "9000"
# Authentik Middleware
traefik.http.middlewares.authentik.forwardauth.address: "http://authentik-server:9000/outpost.goauthentik.io/auth/traefik"
traefik.http.middlewares.authentik.forwardauth.trustForwardHeader: "true"
traefik.http.middlewares.authentik.forwardauth.authResponseHeaders: "X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid,X-authentik-jwt,X-authentik-meta-jwks,X-authentik-meta-outpost,X-authentik-meta-provider,X-authentik-meta-app,X-authentik-meta-version"
# Homepage
homepage.group: "Management"
homepage.name: "Authentik"
homepage.icon: "authentik.svg"
homepage.href: "https://auth.${DOMAIN}"
homepage.description: "Identity Provider"
worker:
image: ghcr.io/goauthentik/server:latest
container_name: authentik-worker
restart: unless-stopped
command: worker
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_POSTGRESQL__HOST: postgresql
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
user: root
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ${CONFIG_ROOT}/authentik/media:/media
- ${CONFIG_ROOT}/authentik/certs:/certs
- ${CONFIG_ROOT}/authentik/custom-templates:/templates
networks:
- authentik_internal
networks:
authentik_internal:
driver: bridge
traefik_public:
external: true

View File

@@ -0,0 +1,45 @@
services:
voidauth:
image: voidauth/voidauth:latest
restart: unless-stopped
volumes:
- ${CONFIG_ROOT}/voidauth/config:/app/config
depends_on:
voidauth-db:
condition: service_healthy
labels:
traefik.enable: 'true'
traefik.http.routers.voidauth.rule: "Host(`auth.${DOMAIN}`)"
traefik.http.routers.voidauth.entryPoints: 'https'
traefik.http.routers.voidauth.tls: 'true'
traefik.http.routers.voidauth.service: "voidauth"
traefik.http.services.voidauth.loadbalancer.server.port: "3000"
traefik.http.middlewares.voidauth.forwardAuth.address: 'http://voidauth:3000/api/authz/forward-auth'
traefik.http.middlewares.voidauth.forwardAuth.trustForwardHeader: 'true'
traefik.http.middlewares.voidauth.forwardAuth.authResponseHeaders: 'Remote-User,Remote-Name,Remote-Email,Remote-Groups'
traefik.docker.network: "traefik_public"
networks:
- internal
- traefik_public
env_file:
- .env
voidauth-db:
image: postgres:18
restart: unless-stopped
environment:
POSTGRES_PASSWORD: # required, same as voidauth DB_PASSWORD
volumes:
- ${CONFIG_ROOT}/voidauth/db:/var/lib/postgresql/18/docker
healthcheck:
test: "pg_isready -U postgres -h localhost"
networks:
- internal
env_file:
- .env
networks:
internal:
driver: bridge
traefik_public:
external: true

View File

@@ -0,0 +1,4 @@
APP_URL: # required, ex. https://auth.example.com
STORAGE_KEY: # required
DB_PASSWORD: # required, same as voidauth-db POSTGRES_PASSWORD
DB_HOST: voidauth-db # required

View File

@@ -0,0 +1,36 @@
services:
zerobyte:
labels:
homepage.group: "Backup"
homepage.name: "Zerobyte"
homepage.icon: "sh-zerobyte.png"
homepage.href: "https://zerobyte.${DOMAIN}"
homepage.description: "Self-hosted backup solution"
traefik.enable: "true"
traefik.http.routers.zerobyte.rule: "Host(`zerobyte.${DOMAIN}`)"
traefik.http.routers.zerobyte.entrypoints: "https"
traefik.http.routers.zerobyte.tls.certresolver: "cloudflare"
traefik.http.routers.zerobyte.service: "zerobyte"
traefik.http.services.zerobyte.loadbalancer.server.port: "4096"
image: ghcr.io/nicotsx/zerobyte:v0.19
container_name: zerobyte
restart: unless-stopped
cap_add:
- SYS_ADMIN
expose:
- "4096"
devices:
- /dev/fuse:/dev/fuse
environment:
- TZ=Europe/London
volumes:
- ${CONFIG_ROOT}/:/container_data
- /etc/localtime:/etc/localtime:ro
- /var/lib/zerobyte:/var/lib/zerobyte
- /home/naivegarmur/.config/rclone:/root/.config/rclone
networks:
- traefik_public
networks:
traefik_public:
external: true

View File

@@ -0,0 +1,4 @@
KARAKEEP_VERSION=latest
NEXTAUTH_SECRET=changeme
MEILI_MASTER_KEY=changeme
GEMINI_API_KEY=changeme

View File

@@ -0,0 +1,76 @@
version: "3.8"
services:
karakeep:
image: ghcr.io/karakeep-app/karakeep:latest
container_name: karakeep
restart: unless-stopped
depends_on:
- meilisearch
- chrome
environment:
- MEILI_ADDR=http://meilisearch:7700
- BROWSER_WEB_URL=http://chrome:9222
- DATA_DIR=/data
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
- NEXTAUTH_URL=https://karakeep.${DOMAIN}
- MEILI_MASTER_KEY=${MEILI_MASTER_KEY}
- OPENAI_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai/
- OPENAI_API_KEY=${GEMINI_API_KEY}
- INFERENCE_TEXT_MODEL=gemini-2.5-flash
- INFERENCE_IMAGE_MODEL=gemini-2.5-flash
- OAUTH_CLIENT_ID=${OAUTH_CLIENT_ID}
- OAUTH_CLIENT_SECRET=${OAUTH_CLIENT_SECRET}
- OAUTH_WELLKNOWN_URL=https://auth.${DOMAIN}/application/o/karakeep/.well-known/openid-configuration
- OAUTH_PROVIDER_NAME=authentik
- OAUTH_ALLOW_DANGEROUS_EMAIL_ACCOUNT_LINKING=true
- DISABLE_PASSWORD_AUTH=true
- DISABLE_SIGNUPS=true
volumes:
- ${CONFIG_ROOT}/karakeep/data:/data
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik_public"
- "traefik.http.routers.karakeep.rule=Host(`karakeep.${DOMAIN}`)"
- "traefik.http.routers.karakeep.entrypoints=https"
- "traefik.http.routers.karakeep.tls.certresolver=cloudflare"
- "traefik.http.services.karakeep.loadbalancer.server.port=3000"
- "homepage.group=Bookmarks"
- "homepage.name=Karakeep"
- "homepage.icon=karakeep.png"
- "homepage.href=https://karakeep.${DOMAIN}"
- "homepage.description=AI Bookmarking Tool"
networks:
- traefik_public
- internal
meilisearch:
image: getmeili/meilisearch:v1.13.3
container_name: karakeep-meilisearch
restart: unless-stopped
environment:
- MEILI_MASTER_KEY=${MEILI_MASTER_KEY}
- MEILI_NO_ANALYTICS=true
volumes:
- ${CONFIG_ROOT}/karakeep/meili_data:/meili_data
networks:
- internal
chrome:
image: gcr.io/zenika-hub/alpine-chrome:124
restart: unless-stopped
command:
- --no-sandbox
- --disable-gpu
- --disable-dev-shm-usage
- --remote-debugging-address=0.0.0.0
- --remote-debugging-port=9222
- --hide-scrollbars
networks:
- internal
networks:
traefik_public:
external: true
internal:
driver: bridge

View File

@@ -0,0 +1,3 @@
BOOKLORE_DB_PASSWORD=secret
BOOKLORE_DB_ROOT_PASSWORD=secret
BOOKLORE_DB_USER=booklore

View File

@@ -0,0 +1,72 @@
services:
booklore:
image: booklore/booklore:latest
# Alternative: Use GitHub Container Registry
# image: ghcr.io/booklore-app/booklore:latest
container_name: booklore
environment:
- USER_ID=${APP_USER_ID}
- GROUP_ID=${APP_GROUP_ID}
- TZ=${TZ}
- DATABASE_URL=${DATABASE_URL}
- DATABASE_USERNAME=${DB_USER}
- DATABASE_PASSWORD=${DB_PASSWORD}
- BOOKLORE_PORT=${BOOKLORE_PORT}
depends_on:
mariadb:
condition: service_healthy
expose:
- "${BOOKLORE_PORT}"
labels:
# Traefik
traefik.enable: "true"
traefik.docker.network: "traefik_public"
traefik.http.routers.booklore.rule: "Host(`booklore.${DOMAIN}`)"
traefik.http.routers.booklore.entrypoints: "https"
traefik.http.routers.booklore.tls.certresolver: "cloudflare"
traefik.http.routers.booklore.service: "booklore"
traefik.http.services.booklore.loadbalancer.server.port: "${BOOKLORE_PORT}"
# Homepage
homepage.group: "Books"
homepage.name: "BookLore"
homepage.icon: "booklore.png"
homepage.href: "https://booklore.${DOMAIN}"
homepage.description: "Book Manager"
networks:
- traefik_public
- default
volumes:
- ${CONFIG_ROOT}/booklore/data:/app/data
- ${MEDIA_PATH}/books:/books
- ${MEDIA_PATH}/bookdrop:/bookdrop
healthcheck:
test: wget -q -O - http://localhost:${BOOKLORE_PORT}/api/v1/healthcheck
interval: 60s
retries: 5
start_period: 60s
timeout: 10s
restart: unless-stopped
mariadb:
image: lscr.io/linuxserver/mariadb:11.4.5
container_name: mariadb
environment:
- PUID=${DB_USER_ID}
- PGID=${DB_GROUP_ID}
- TZ=${TZ}
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${DB_USER}
- MYSQL_PASSWORD=${DB_PASSWORD}
volumes:
- ./mariadb/config:/config
restart: unless-stopped
healthcheck:
test: [ "CMD", "mariadb-admin", "ping", "-h", "localhost" ]
interval: 5s
timeout: 5s
retries: 10
networks:
traefik_public:
external: true

View File

@@ -0,0 +1,88 @@
################################
# 🦎 KOMODO COMPOSE - MONGO 🦎 #
################################
## This compose file will deploy:
## 1. MongoDB
## 2. Komodo Core
## 3. Komodo Periphery
services:
mongo:
image: mongo
labels:
komodo.skip: # Prevent Komodo from stopping with StopAllContainers
command: --quiet --wiredTigerCacheSizeGB 0.25
restart: unless-stopped
# ports:
# - 27017:27017
volumes:
- ${CONFIG_ROOT}/komodo/mongo-data:/data/db
- ${CONFIG_ROOT}/komodo/mongo-config:/data/configdb
environment:
MONGO_INITDB_ROOT_USERNAME: ${KOMODO_DB_USERNAME}
MONGO_INITDB_ROOT_PASSWORD: ${KOMODO_DB_PASSWORD}
networks:
- internal
core:
image: ghcr.io/moghtech/komodo-core:${COMPOSE_KOMODO_IMAGE_TAG:-latest}
labels:
komodo.skip: # Prevent Komodo from stopping with StopAllContainers
traefik.enable: "true"
traefik.http.routers.komodo.rule: "Host(`containers.${DOMAIN}`)"
traefik.http.routers.komodo.entrypoints: "https"
traefik.http.routers.komodo.tls.certresolver: "cloudflare"
traefik.http.routers.komodo.service: "komodo"
traefik.http.services.komodo.loadbalancer.server.port: "9120"
traefik.docker.network: "traefik_public"
restart: unless-stopped
depends_on:
- mongo
env_file: ./compose.env
environment:
KOMODO_DATABASE_ADDRESS: mongo:27017
KOMODO_DATABASE_USERNAME: ${KOMODO_DB_USERNAME}
KOMODO_DATABASE_PASSWORD: ${KOMODO_DB_PASSWORD}
volumes:
## Store dated backups of the database - https://komo.do/docs/setup/backup
- ${COMPOSE_KOMODO_BACKUPS_PATH}:/backups
## Store sync files on server
- ${CONFIG_ROOT}/komodo/syncs:/syncs
## Optionally mount a custom core.config.toml
# - /path/to/core.config.toml:/config/config.toml
## Allows for systemd Periphery connection at
## "https://host.docker.internal:8120"
# extra_hosts:
# - host.docker.internal:host-gateway
networks:
- internal
- traefik_public
## Deploy Periphery container using this block,
## or deploy the Periphery binary with systemd using
## https://github.com/moghtech/komodo/tree/main/scripts
periphery:
image: ghcr.io/moghtech/komodo-periphery:${COMPOSE_KOMODO_IMAGE_TAG:-latest}
labels:
komodo.skip: # Prevent Komodo from stopping with StopAllContainers
restart: unless-stopped
env_file: ./compose.env
volumes:
## Mount external docker socket
- /var/run/docker.sock:/var/run/docker.sock
## Allow Periphery to see processes outside of container
- /proc:/proc
## Specify the Periphery agent root directory.
## Must be the same inside and outside the container,
## or docker will get confused. See https://github.com/moghtech/komodo/discussions/180.
## Default: /etc/komodo.
- ${PERIPHERY_ROOT_DIRECTORY:-/etc/komodo}:${PERIPHERY_ROOT_DIRECTORY:-/etc/komodo}
networks:
- internal
networks:
traefik_public:
external: true
internal:
driver: bridge

View File

@@ -1,19 +0,0 @@
services:
portainer:
container_name: portainer
image: portainer/portainer-ce:lts
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer_data:/data
ports:
- 9443:9443
- 8000:8000 # Remove if you do not intend to use Edge Agents
volumes:
portainer_data:
name: portainer_data
networks:
default:
name: kendricklab

View File

@@ -0,0 +1,24 @@
services:
glance:
container_name: glance
image: glanceapp/glance
restart: unless-stopped
volumes:
- ${CONFIG_ROOT}/glance/config:/app/config
- ${CONFIG_ROOT}/glance/assets:/app/assets
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
env_file: .env
networks:
- traefik_public
labels:
traefik.enable: "true"
traefik.http.routers.glance.rule: "Host(`glance.${DOMAIN}`)"
traefik.http.routers.glance.entrypoints: "https"
traefik.http.routers.glance.tls.certresolver: "cloudflare"
traefik.http.routers.glance.service: "glance"
traefik.http.services.glance.loadbalancer.server.port: "8080"
networks:
traefik_public:
external: true

View File

@@ -0,0 +1,21 @@
services:
adguardhome:
container_name: adguardhome
image: adguard/adguardhome
restart: unless-stopped
labels:
homepage.group: "DNS"
homepage.name: "AdGuard Home"
homepage.icon: "adguard-home.png"
homepage.href: "https://adguard.${DOMAIN}"
homepage.description: "DNS Sinkhole"
traefik.enable: "true"
traefik.http.routers.adguard.rule: "Host(`adguard.${DOMAIN}`)"
traefik.http.routers.adguard.entrypoints: "https"
traefik.http.routers.adguard.tls.certresolver: "cloudflare"
traefik.http.routers.adguard.middlewares: "voidauth@docker"
traefik.http.services.adguard.loadbalancer.server.address: "http://${HOST_IP}:6969"
network_mode: host
volumes:
- ${CONFIG_ROOT}/adguard/work:/opt/adguardhome/work
- ${CONFIG_ROOT}/adguard/conf:/opt/adguardhome/conf

View File

@@ -0,0 +1,68 @@
version: "3.8"
services:
broker:
image: docker.io/library/redis:7
container_name: paperless_redis
restart: unless-stopped
volumes:
- ${CONFIG_ROOT}/paperless/redis:/data
db:
image: docker.io/library/postgres:16
container_name: paperless_db
restart: unless-stopped
volumes:
- ${CONFIG_ROOT}/paperless/pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: paperless
POSTGRES_USER: paperless
POSTGRES_PASSWORD: ${PAPERLESS_DB_PASS:-paperless}
webserver:
image: ghcr.io/paperless-ngx/paperless-ngx:latest
container_name: paperless
restart: unless-stopped
depends_on:
- db
- broker
environment:
PAPERLESS_REDIS: redis://broker:6379
PAPERLESS_DBHOST: db
PAPERLESS_DBPORT: 5432
PAPERLESS_DBNAME: paperless
PAPERLESS_DBUSER: paperless
PAPERLESS_DBPASS: ${PAPERLESS_DB_PASS:-paperless}
PAPERLESS_SECRET_KEY: ${PAPERLESS_SECRET_KEY}
PAPERLESS_URL: https://paperless.${DOMAIN}
PAPERLESS_TIME_ZONE: ${TZ:-Etc/UTC}
PAPERLESS_OCR_ROTATE_PAGES: clean
USERMAP_UID: ${PUID:-1000}
USERMAP_GID: ${PGID:-1000}
volumes:
- ${CONFIG_ROOT}/paperless/data:/usr/src/paperless/data
- ${CONFIG_ROOT}/paperless/media:/usr/src/paperless/media
- ${CONFIG_ROOT}/paperless/export:/usr/src/paperless/export
- ${CONFIG_ROOT}/paperless/consume:/usr/src/paperless/consume
labels:
# Traefik
traefik.enable: "true"
traefik.docker.network: "traefik_public"
traefik.http.routers.paperless.rule: "Host(`paperless.${DOMAIN}`)"
traefik.http.routers.paperless.entrypoints: "https"
traefik.http.routers.paperless.service: "paperless"
traefik.http.routers.paperless.tls.certresolver: "cloudflare"
traefik.http.services.paperless.loadbalancer.server.port: "8000"
# Homepage
homepage.group: "Documents"
homepage.name: "Paperless-ngx"
homepage.icon: "paperless-ngx.svg"
homepage.href: "https://paperless.${DOMAIN}"
homepage.description: "Document Management"
networks:
- traefik_public
- default
networks:
traefik_public:
external: true

View File

@@ -0,0 +1,37 @@
version: "3.8"
services:
mealie:
image: ghcr.io/mealie-recipes/mealie:latest
container_name: mealie
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
- BASE_URL=https://mealie.${DOMAIN}
- ALLOW_SIGNUP=true
volumes:
- ${CONFIG_ROOT}/mealie/data:/app/data
expose:
- 9000
labels:
# Traefik
traefik.enable: "true"
traefik.http.routers.mealie.rule: "Host(`mealie.${DOMAIN}`)"
traefik.http.routers.mealie.entrypoints: "https"
traefik.http.routers.mealie.tls.certresolver: "cloudflare"
traefik.http.routers.mealie.service: "mealie"
traefik.http.services.mealie.loadbalancer.server.port: "9000"
# Homepage
homepage.group: "Food"
homepage.name: "Mealie"
homepage.icon: "mealie.png"
homepage.href: "https://mealie.${DOMAIN}"
homepage.description: "Recipe Manager"
networks:
- traefik_public
networks:
traefik_public:
external: true

View File

@@ -0,0 +1,25 @@
services:
core-keeper:
image: escaping/core-keeper-dedicated:latest
container_name: core-keeper-dedicated
restart: unless-stopped
labels:
homepage.group: "Games"
homepage.name: "Core Keeper"
homepage.icon: "https://cdn2.steamgriddb.com/icon/f21e81ff7fd73e8ed6cc5240d53263be.ico"
homepage.description: "Game Server"
stop_grace_period: 2m
# Port is only needed if using direct connection mode
# ports:
# - "$SERVER_PORT:$SERVER_PORT/udp"
volumes:
- ${CONFIG_ROOT}/core-keeper/server-files:/home/steam/core-keeper-dedicated
- ${CONFIG_ROOT}/core-keeper/server-data:/home/steam/core-keeper-data
environment:
- DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/1449377878192947241/_fBMK0aw42CB4WCae-xJZSI887APRjOGCB1XwYK9gDEMPVdHeqH2OncvCNg9q1VNxDVn
networks:
- traefik_public
networks:
traefik_public:
external: true

View File

@@ -0,0 +1,52 @@
version: "3"
services:
server:
image: docker.io/awinterstein/habitica-server:latest
restart: unless-stopped
depends_on:
- mongo
environment:
- NODE_DB_URI=mongodb://mongo/habitica
- BASE_URL
- INVITE_ONLY # change to `true` after registration of initial users, to restrict further registrations
- EMAIL_SERVER_URL
- EMAIL_SERVER_PORT
- EMAIL_SERVER_AUTH_USER
- EMAIL_SERVER_AUTH_PASSWORD
- ADMIN_EMAIL
networks:
- traefik_public
- habitica
labels:
traefik.enable: "true"
traefik.docker.network: "traefik_public"
traefik.http.routers.habitica.rule: "Host(`habitica.${DOMAIN}`)"
traefik.http.routers.habitica.entrypoints: "https"
traefik.http.routers.habitica.tls.certresolver: "cloudflare"
traefik.http.routers.habitica.service: "habitica"
traefik.http.services.habitica.loadbalancer.server.port: "3000"
mongo:
image: docker.io/mongo:latest # better to replace 'latest' with the concrete mongo version (e.g., the most recent one)
restart: unless-stopped
hostname: mongo
command: ["--replSet", "rs", "--bind_ip_all", "--port", "27017"]
healthcheck:
test: echo "try { rs.status() } catch (err) { rs.initiate() }" | mongosh --port 27017 --quiet
interval: 10s
timeout: 30s
start_period: 0s
start_interval: 1s
retries: 30
volumes:
- ${CONFIG_ROOT}/habitica/db:/data/db:rw
- ${CONFIG_ROOT}/habitica/dbconf:/data/configdb
networks:
habitica:
aliases:
- mongo
networks:
habitica:
driver: bridge
traefik_public:
external: true

View File

@@ -0,0 +1,144 @@
version: "3.8"
services:
gluetun:
image: qmcgaw/gluetun
container_name: gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
environment:
- FIREWALL_OUTBOUND_SUBNETS=172.29.0.0/16,192.168.0.0/16
- VPN_SERVICE_PROVIDER=protonvpn
- VPN_TYPE=wireguard
- WIREGUARD_PRIVATE_KEY=${PROTONVPN_WIREGUARD_PRIVATE_KEY}
- SERVER_COUNTRIES=Denmark
# - OPENVPN_USER=${PROTON_OPENVPN_USER}
# - OPENVPN_PASS=${PROTON_OPENVPN_PASS}
volumes:
- ${CONFIG_ROOT}/gluetun:/gluetun
ports:
- 7878:7878 # Radarr
- 8989:8989 # Sonarr
- 9696:9696 # Prowlarr
- 6789:6789 # NZBGet
restart: unless-stopped
networks:
- traefik_public
radarr:
image: lscr.io/linuxserver/radarr:latest
container_name: radarr
network_mode: service:gluetun
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
volumes:
- ${CONFIG_ROOT}/radarr:/config
- ${MEDIA_PATH}:/media
restart: unless-stopped
labels:
# Traefik
traefik.enable: "true"
traefik.http.routers.radarr.rule: "Host(`radarr.${DOMAIN}`)"
traefik.http.routers.radarr.entrypoints: "https"
traefik.http.routers.radarr.service: "radarr"
traefik.http.routers.radarr.tls.certresolver: "cloudflare"
traefik.http.routers.radarr.middlewares: "voidauth@docker"
traefik.http.services.radarr.loadbalancer.server.port: "7878"
# Homepage
homepage.group: "Media"
homepage.name: "Radarr"
homepage.icon: "radarr.svg"
homepage.href: "https://radarr.${DOMAIN}"
homepage.description: "Movie Manager"
sonarr:
image: lscr.io/linuxserver/sonarr:latest
container_name: sonarr
network_mode: service:gluetun
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
volumes:
- ${CONFIG_ROOT}/sonarr:/config
- ${MEDIA_PATH}:/media
restart: unless-stopped
labels:
# Traefik
traefik.enable: "true"
traefik.http.routers.sonarr.rule: "Host(`sonarr.${DOMAIN}`)"
traefik.http.routers.sonarr.entrypoints: "https"
traefik.http.routers.sonarr.service: "sonarr"
traefik.http.routers.sonarr.tls.certresolver: "cloudflare"
traefik.http.routers.sonarr.middlewares: "voidauth@docker"
traefik.http.services.sonarr.loadbalancer.server.port: "8989"
# Homepage
homepage.group: "Media"
homepage.name: "Sonarr"
homepage.icon: "sonarr.svg"
homepage.href: "https://sonarr.${DOMAIN}"
homepage.description: "TV Series Manager"
prowlarr:
image: lscr.io/linuxserver/prowlarr:latest
container_name: prowlarr
network_mode: service:gluetun
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
volumes:
- ${CONFIG_ROOT}/prowlarr:/config
restart: unless-stopped
labels:
# Traefik
traefik.enable: "true"
traefik.http.routers.prowlarr.rule: "Host(`prowlarr.${DOMAIN}`)"
traefik.http.routers.prowlarr.entrypoints: "https"
traefik.http.routers.prowlarr.service: "prowlarr"
traefik.http.routers.prowlarr.middlewares: "voidauth@docker"
traefik.http.routers.prowlarr.tls.certresolver: "cloudflare"
traefik.http.services.prowlarr.loadbalancer.server.port: "9696"
# Homepage
homepage.group: "Media"
homepage.name: "Prowlarr"
homepage.icon: "prowlarr.svg"
homepage.href: "https://prowlarr.${DOMAIN}"
homepage.description: "Indexer Manager"
nzbget:
image: lscr.io/linuxserver/nzbget:latest
container_name: nzbget
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
volumes:
- ${CONFIG_ROOT}/nzbget:/config
- ${MEDIA_PATH}:/media # Downloads location
restart: unless-stopped
labels:
# Traefik
traefik.enable: "true"
traefik.http.routers.nzbget.rule: "Host(`nzbget.${DOMAIN}`)"
traefik.http.routers.nzbget.entrypoints: "https"
traefik.http.routers.nzbget.service: "nzbget"
traefik.http.routers.nzbget.tls.certresolver: "cloudflare"
traefik.http.routers.nzbget.middlewares: "voidauth@docker"
traefik.http.services.nzbget.loadbalancer.server.port: "6789"
# Homepage
homepage.group: "Media"
homepage.name: "NZBGet"
homepage.icon: "nzbget.svg"
homepage.href: "https://nzbget.${DOMAIN}"
homepage.description: "Usenet Downloader"
networks:
- traefik_public
networks:
traefik_public:
external: true

View File

@@ -0,0 +1,32 @@
version: "3.8"
services:
audiobookshelf:
image: ghcr.io/advplyr/audiobookshelf:latest
container_name: audiobookshelf
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
volumes:
- ${DOCKER_PATH}/audiobookshelf/config:/config
- ${DOCKER_PATH}/audiobookshelf/metadata:/metadata
- ${MEDIA_PATH}/audiobooks:/audiobooks
- ${MEDIA_PATH}/podcasts:/podcasts
expose:
- 80
restart: unless-stopped
labels:
# Traefik
traefik.enable: "true"
traefik.http.routers.audiobookshelf.rule: "Host(`audiobookshelf.${DOMAIN}`)"
traefik.http.routers.audiobookshelf.entrypoints: "https"
traefik.http.routers.audiobookshelf.service: "audiobookshelf"
traefik.http.routers.audiobookshelf.tls.certresolver: "cloudflare"
traefik.http.services.audiobookshelf.loadbalancer.server.port: "80"
networks:
- traefik_public
networks:
traefik_public:
external: true

View File

@@ -0,0 +1,69 @@
version: "3.8"
services:
jellyfin:
image: jellyfin/jellyfin
container_name: jellyfin
devices:
- /dev/dri/renderD128:/dev/dri/renderD128
- /dev/dri/card1:/dev/dri/card1
group_add:
- "992" # Replace this with your host's 'render' group ID
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
volumes:
- ${DOCKER_PATH}/jellyfin/config:/config
- ${MEDIA_PATH}:/media
expose:
- 8096
restart: unless-stopped
labels:
# Traefik
traefik.enable: "true"
traefik.http.routers.jellyfin.rule: "Host(`jellyfin.${DOMAIN}`)"
traefik.http.routers.jellyfin.entrypoints: "https"
traefik.http.routers.jellyfin.service: "jellyfin"
traefik.http.routers.jellyfin.tls.certresolver: "cloudflare"
traefik.http.services.jellyfin.loadbalancer.server.port: "8096"
# Homepage
homepage.group: "Media"
homepage.name: "Jellyfin"
homepage.icon: "jellyfin.svg"
homepage.href: "https://jellyfin.${DOMAIN}"
homepage.description: "Media Server"
networks:
- traefik_public
jellyseerr:
image: fallenbagel/jellyseerr
container_name: jellyseerr
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
volumes:
- ${DOCKER_PATH}/jellyseerr/config:/app/config
expose:
- 5055
restart: unless-stopped
labels:
# Traefik
traefik.enable: "true"
traefik.http.routers.jellyseerr.rule: "Host(`jellyseerr.${DOMAIN}`)"
traefik.http.routers.jellyseerr.entrypoints: "https"
traefik.http.routers.jellyseerr.service: "jellyseerr"
traefik.http.routers.jellyseerr.tls.certresolver: "cloudflare"
traefik.http.services.jellyseerr.loadbalancer.server.port: "5055"
# Homepage
homepage.group: "Media"
homepage.name: "Jellyseerr"
homepage.icon: "jellyseerr.svg"
homepage.href: "https://jellyseerr.${DOMAIN}"
homepage.description: "Request management"
networks:
- traefik_public
networks:
traefik_public:
external: true

View File

@@ -0,0 +1,3 @@
JELLYSTAT_DB_USER=postgres
JELLYSTAT_DB_PASSWORD=change_me
JELLYSTAT_JWT_SECRET=change_me_to_a_random_string

View File

@@ -0,0 +1,52 @@
version: "3.8"
services:
jellystat-db:
image: postgres:15
container_name: jellystat-db
environment:
POSTGRES_DB: jfstat
POSTGRES_USER: ${JELLYSTAT_DB_USER:-postgres}
POSTGRES_PASSWORD: ${JELLYSTAT_DB_PASSWORD}
volumes:
- ${DOCKER_PATH}/jellystat/postgres:/var/lib/postgresql/data
restart: unless-stopped
networks:
- traefik_public
jellystat:
image: cyfershepard/jellystat:latest
container_name: jellystat
environment:
POSTGRES_USER: ${JELLYSTAT_DB_USER:-postgres}
POSTGRES_PASSWORD: ${JELLYSTAT_DB_PASSWORD}
POSTGRES_IP: jellystat-db
POSTGRES_PORT: 5432
JWT_SECRET: ${JELLYSTAT_JWT_SECRET}
volumes:
- ${DOCKER_PATH}/jellystat/backup:/app/backend/backup-data
depends_on:
- jellystat-db
expose:
- 3000
restart: unless-stopped
labels:
# Traefik
traefik.enable: "true"
traefik.http.routers.jellystat.rule: "Host(`jellystat.${DOMAIN}`)"
traefik.http.routers.jellystat.entrypoints: "https"
traefik.http.routers.jellystat.service: "jellystat"
traefik.http.routers.jellystat.tls.certresolver: "cloudflare"
traefik.http.services.jellystat.loadbalancer.server.port: "3000"
# Homepage
homepage.group: "Media"
homepage.name: "Jellystat"
homepage.icon: "jellystat.png"
homepage.href: "https://jellystat.${DOMAIN}"
homepage.description: "Jellyfin Statistics"
networks:
- traefik_public
networks:
traefik_public:
external: true

View File

@@ -0,0 +1,36 @@
version: "3.8"
services:
jellysweep:
image: ghcr.io/jon4hz/jellysweep:latest
container_name: jellysweep
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
volumes:
- ${DOCKER_PATH}/jellysweep/config.yml:/app/config.yml:ro
- ${MEDIA_PATH}:/media
expose:
- 3002
restart: unless-stopped
labels:
# Traefik
traefik.enable: "true"
traefik.http.routers.jellysweep.rule: "Host(`jellysweep.${DOMAIN}`)"
traefik.http.routers.jellysweep.entrypoints: "https"
traefik.http.routers.jellysweep.service: "jellysweep"
traefik.http.routers.jellysweep.tls.certresolver: "cloudflare"
traefik.http.services.jellysweep.loadbalancer.server.port: "3002"
# Homepage
homepage.group: "Media"
homepage.name: "Jellysweep"
homepage.icon: "jellyfin.svg" # Using Jellyfin icon as placeholder
homepage.href: "https://jellysweep.${DOMAIN}"
homepage.description: "Jellyfin Cleanup Tool"
networks:
- traefik_public
networks:
traefik_public:
external: true

View File

@@ -0,0 +1,14 @@
jellyfin:
url: "http://jellyfin:8096" # Internal docker DNS if on same network, or full URL
token: "YOUR_JELLYFIN_API_KEY"
# dry_run: true # Set to false to actually delete files
# Library configuration
libraries:
- name: Movies
keep: 1
age: 30d # Delete movies older than 30 days
- name: TV Shows
keep: 1
age: 30d

View File

@@ -0,0 +1,39 @@
services:
beszel:
image: 'henrygd/beszel'
container_name: beszel
restart: unless-stopped
volumes:
- ${CONFIG_ROOT}/beszel/data:/beszel_data
labels:
homepage.group: "Monitoring"
homepage.name: "Beszel"
homepage.icon: "beszel.png"
homepage.href: "https://beszel.${DOMAIN}"
homepage.description: "Lightweight Server Monitoring"
traefik.enable: "true"
traefik.http.routers.beszel.rule: "Host(`beszel.${DOMAIN}`)"
traefik.http.routers.beszel.entrypoints: "https"
traefik.http.routers.beszel.tls.certresolver: "cloudflare"
traefik.http.routers.beszel.service: "beszel"
traefik.http.services.beszel.loadbalancer.server.port: "8090"
networks:
- traefik_public
beszel-agent:
image: henrygd/beszel-agent
container_name: beszel-agent
restart: unless-stopped
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ${CONFIG_ROOT}/beszel_agent_data:/var/lib/beszel-agent
environment:
LISTEN: 45876
KEY: ${BESZEL_KEY}
TOKEN: ${BESZEL_TOKEN}
HUB_URL: https://beszel.${DOMAIN}
networks:
traefik_public:
external: true

View File

@@ -0,0 +1,21 @@
services:
monitoring:
image: nicolargo/glances:ubuntu-latest-full
pid: host
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /run/user/1000/podman/podman.sock:/run/user/1000/podman/podman.sock
labels:
homepage.group: "Monitoring"
homepage.name: "Glances"
homepage.icon: "glances.png"
homepage.href: "https://glances.${DOMAIN}"
homepage.description: "System Monitoring"
traefik.enable: "true"
traefik.http.routers.glances.rule: "Host(`glances.${DOMAIN}`)"
traefik.http.routers.glances.entrypoints: "https"
traefik.http.routers.glances.tls.certresolver: "cloudflare"
traefik.http.services.glances.loadbalancer.server.url: "http://${HOST_IP}:61208"
environment:
- "GLANCES_OPT=-w"

View File

@@ -0,0 +1,32 @@
services:
speedtest-tracker:
image: lscr.io/linuxserver/speedtest-tracker:latest
restart: unless-stopped
container_name: speedtest-tracker
environment:
- PUID=1000
- PGID=1000
- APP_KEY=${APP_KEY}
- DB_CONNECTION=sqlite
- SPEEDTEST_SCHEDULE=0 * * * *
- APP_TIMEZONE=Europe/London
volumes:
- ${CONFIG_ROOT}/speedtest-tracker:/config
networks:
- traefik_public
labels:
homepage.group: "Monitoring"
homepage.name: "Speedtest Tracker"
homepage.icon: "sh-speedtest-tracker.png"
homepage.href: "https://speedtest.${DOMAIN}"
homepage.description: "Internet speed tracking"
traefik.enable: "true"
traefik.http.routers.speedtest-tracker.rule: "Host(`speedtest.${DOMAIN}`)"
traefik.http.routers.speedtest-tracker.entrypoints: "https"
traefik.http.routers.speedtest-tracker.tls.certresolver: "cloudflare"
traefik.http.routers.speedtest-tracker.service: "speedtest-tracker"
traefik.http.services.speedtest-tracker.loadbalancer.server.port: "80"
networks:
traefik_public:
external: true

View File

@@ -0,0 +1,32 @@
services:
uptime-kuma:
container_name: uptime-kuma
image: louislam/uptime-kuma:2
restart: unless-stopped
volumes:
- ${CONFIG_ROOT}/uptime-kuma:/app/data
- /var/run/docker.sock:/var/run/docker.sock
labels:
homepage.group: "Monitoring"
homepage.name: "Uptime Kuma"
homepage.icon: "uptime-kuma.png"
homepage.href: "https://status.${DOMAIN}/status/homelab"
homepage.description: "Uptime Monitoring"
homepage.widget.type: "uptimekuma"
homepage.widget.url: "https://status.kendricklab.uk/"
homepage.widget.slug: "homelab"
traefik.enable: "true"
traefik.http.routers.uptime-kuma.rule: "Host(`status.${DOMAIN}`)"
traefik.http.routers.uptime-kuma.entrypoints: "https"
traefik.http.routers.uptime-kuma.tls.certresolver: "cloudflare"
traefik.http.routers.uptime-kuma.service: "uptime-kuma"
traefik.http.services.uptime-kuma.loadbalancer.server.port: "3001"
expose:
# <Host Port>:<Container Port>
- "3001"
networks:
- traefik_public
networks:
traefik_public:
external: true

View File

@@ -1,28 +0,0 @@
name: "Nginx Proxy Manager"
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
# These ports are in format <host-port>:<container-port>
- '80:80' # Public HTTP Port
- '443:443' # Public HTTPS Port
- '81:81' # Admin Web Port
# Add any other Stream port you want to expose
# - '21:21' # FTP
environment:
TZ: "Europe/London"
# Uncomment this if you want to change the location of
# the SQLite DB file within the container
# DB_SQLITE_FILE: "/data/database.sqlite"
# Uncomment this if IPv6 is not enabled on your host
# DISABLE_IPV6: 'true'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt

View File

@@ -0,0 +1,45 @@
version: '3.8'
services:
traefik:
image: traefik:latest
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
ports:
- "80:80"
- "443:443"
environment:
- CF_DNS_API_TOKEN_FILE=/run/secrets/cf_dns_api_token
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ${CONFIG_ROOT}/traefik/traefik.yml:/traefik.yml:ro
- ${CONFIG_ROOT}/traefik/acme.json:/acme.json
- ${CONFIG_ROOT}/traefik/logs:/var/log/traefik
- ${CONFIG_ROOT}/traefik/dynamic:/etc/traefik/dynamic:ro
secrets:
- cf_dns_api_token
labels:
# Homepage
- "homepage.group=Proxies"
- "homepage.name=Traefik"
- "homepage.icon=traefik.svg"
- "homepage.href=https://traefik.${DOMAIN}"
- "homepage.description=Traefik Dashboard"
# Dashboard
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN}`)"
- "traefik.http.routers.traefik.entrypoints=https"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.routers.traefik.tls.certresolver=cloudflare"
networks:
- traefik_public
networks:
traefik_public:
name: traefik_public
secrets:
cf_dns_api_token:
file: ${CONFIG_ROOT}/traefik/secrets/cf_dns_api_token

View File

@@ -0,0 +1,22 @@
services:
cloudflared:
image: cloudflare/cloudflared:latest
container_name: cloudflared
restart: unless-stopped
command: tunnel run
volumes:
- ${CONFIG_ROOT}/cloudflared:/etc/cloudflared
environment:
- TUNNEL_TOKEN=${TUNNEL_TOKEN}
labels:
homepage.group: "Remote Access"
homepage.name: "Cloudflared"
homepage.icon: "cloudflare.png"
homepage.href: "https://one.dash.cloudflare.com"
homepage.description: "Cloudflare Tunnel"
networks:
- traefik_public
networks:
traefik_public:
external: true

View File

@@ -0,0 +1,39 @@
version: "3.9"
services:
frigate:
container_name: frigate
image: ghcr.io/blakeblackshear/frigate:stable
shm_size: "512mb" # Update based on camera resolution and count
privileged: true # Add this
devices:
- /dev/dri:/dev/dri # For Intel hardware acceleration
# - /dev/bus/usb:/dev/bus/usb # Google Coral USB
volumes:
- /etc/localtime:/etc/localtime:ro
- ${CONFIG_ROOT}/frigate:/config
- ${CONFIG_ROOT}/frigate/storage:/media/frigate
- type: tmpfs
target: /tmp/cache
tmpfs:
size: 1000000000
ports:
- "5000:5000"
- "8554:8554" # RTSP feeds
- "8555:8555/tcp" # WebRTC
- "8555:8555/udp" # WebRTC
restart: unless-stopped
labels:
# Traefik
traefik.enable: "true"
traefik.http.routers.frigate.rule: "Host(`frigate.${DOMAIN}`)"
traefik.http.routers.frigate.entrypoints: "https"
traefik.http.routers.frigate.service: "frigate"
traefik.http.routers.frigate.tls.certresolver: "cloudflare"
traefik.http.services.frigate.loadbalancer.server.port: "5000"
# Homepage
homepage.group: "Security"
homepage.name: "Frigate"
homepage.icon: "frigate.svg"
homepage.href: "https://frigate.${DOMAIN}"
homepage.description: "NVR with AI object detection"

View File

@@ -0,0 +1,43 @@
version: "3"
networks:
traefik_public:
external: true
services:
server:
image: docker.gitea.com/gitea:1.25.2
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
restart: always
labels:
homepage.group: "Version Control"
homepage.name: "Gitea"
homepage.icon: "gitea.png"
homepage.href: "https://gitea.${DOMAIN}"
homepage.description: "Git Server"
traefik.enable: "true"
# Web
traefik.http.routers.gitea.rule: "Host(`gitea.${DOMAIN}`)"
traefik.http.routers.gitea.entrypoints: "https"
traefik.http.routers.gitea.tls.certresolver: "cloudflare"
traefik.http.routers.gitea.service: "gitea"
traefik.http.services.gitea.loadbalancer.server.port: "3000"
# SSH
traefik.tcp.routers.gitea-ssh.rule: "HostSNI(`git.${DOMAIN}`)"
traefik.tcp.routers.gitea-ssh.entrypoints: "https"
traefik.tcp.routers.gitea-ssh.service: "gitea-ssh"
traefik.tcp.routers.gitea-ssh.tls.passthrough: "true"
traefik.tcp.services.gitea-ssh.loadbalancer.server.address: "${HOST_IP}:222"
networks:
- traefik_public
volumes:
- ${CONFIG_ROOT}/gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
expose:
- "3000"
ports:
- "222:22"