Compare commits

...

79 Commits

Author SHA1 Message Date
dde45742e1 updated port
Some checks failed
Deploy All Stacks to Swarm / deploy (push) Failing after 8s
2025-11-12 18:09:11 -05:00
0b93862185
Some checks failed
Deploy All Stacks to Swarm / deploy (push) Failing after 8s
2025-11-12 18:06:29 -05:00
d5e8a573ad update service 2025-11-12 18:06:10 -05:00
36b949d9c7 removed rsync service
All checks were successful
Deploy All Stacks to Swarm / deploy (push) Successful in 20s
2025-11-12 22:59:05 +00:00
5a495cb8ee Add deployment workflow
Some checks failed
Deploy All Stacks to Swarm / deploy (push) Has been cancelled
2025-11-12 22:55:10 +00:00
3e30c33fbe staging for gitea runner
Some checks failed
Deploy Stack to Swarm / deploy (push) Failing after 58s
2025-11-12 17:46:19 -05:00
b0a4f23cad
Some checks failed
Deploy Stack to Swarm / deploy (push) Has been cancelled
2025-11-12 22:40:02 +00:00
d02148af76 2025-11-12 22:19:14 +00:00
a150527d95 updated mounts 2025-11-12 22:02:23 +00:00
b8a5345d68 Merge branch 'main' of github.com:ghost062591/swarm-production 2025-11-12 16:54:41 -05:00
3a6bfa0854 Fixed Mount 2025-11-12 06:42:29 -05:00
cb73a13e48 Fixed Mount 2025-11-12 06:40:03 -05:00
08ebe28456 2025-11-12 06:25:31 -05:00
6c2dd888bb fixed mount 2025-11-12 06:25:08 -05:00
bc097a98de 2025-11-12 06:12:07 -05:00
18c04db9bb Migrated Emby data to swarm 2025-11-12 06:07:46 -05:00
8dfe1a8310 2025-11-11 21:02:39 -05:00
f649d4dcb7 2025-11-11 20:50:39 -05:00
26fcb257d5 2025-11-11 20:42:38 -05:00
6a47ec2ed6 2025-11-11 20:42:16 -05:00
08a1882232 changed config directory 2025-11-11 20:38:28 -05:00
f5bccb9f3b Testing Gitea webhooks 2025-11-11 20:27:44 -05:00
05e0febeb4 2025-11-11 19:35:59 -05:00
0055e31123 2025-11-11 19:30:25 -05:00
76cdb88226 2025-11-11 18:32:12 -05:00
51edbebf28 Traefik 2025-11-11 18:25:39 -05:00
1a75b85508 2025-11-11 18:17:42 -05:00
ecbb8d0da4 2025-11-11 18:11:42 -05:00
8b634466b2 2025-11-11 18:08:11 -05:00
a22e1307ae 2025-11-11 18:04:55 -05:00
72ffc356b4 test 2025-11-11 15:31:47 -05:00
f44d53cab9 test 2025-11-11 15:30:30 -05:00
1e6132437f test 2025-11-11 15:23:43 -05:00
d4ce82d48d 2025-11-11 15:18:42 -05:00
2c050791db test 2025-11-11 15:13:04 -05:00
77c33e6217 test 2025-11-11 15:11:45 -05:00
22b321ae74 Added Traefik labels for proxy 2025-11-11 14:38:42 -05:00
af38c71fb0 core services stack 2025-11-11 14:13:08 -05:00
1d3a67a56c remove test 2025-11-11 18:45:09 +00:00
d1e9ca973b test 2025-11-11 18:43:09 +00:00
cec2cb6742 2025-11-11 15:29:52 +00:00
8595c769b0 2025-11-11 11:33:49 +00:00
8e5d39ebae 2025-11-11 10:22:16 +00:00
4dfbbea537 2025-11-11 10:16:27 +00:00
2c6c89a2af 2025-11-11 10:13:27 +00:00
601773bc39 2025-11-11 10:06:25 +00:00
ea0de92f0f 2025-11-11 10:04:13 +00:00
3207c27617 2025-11-11 09:58:12 +00:00
04297fa8dd 2025-11-11 09:57:24 +00:00
195cbafcf7 2025-11-11 09:55:05 +00:00
d16905c71a 2025-11-11 09:53:16 +00:00
eee375d07b 2025-11-11 09:49:51 +00:00
8cba1e7fd3 2025-11-11 02:09:39 +00:00
0f75fbf226 Fix PostgreSQL stack configuration
- Remove invalid PUID/PUIG environment variables (not supported by official Postgres image)
- Fix service name from 'postgres' to 'postgresSQL' to match configuration references
- Resolve permission errors on data directory mount

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 01:44:46 +00:00
95c867bf69 permissions 2025-11-11 01:39:32 +00:00
7f24735ead updated with secrets 2025-11-11 01:36:00 +00:00
e2060a70ec unraid to swarm migration 2025-11-11 01:25:04 +00:00
6a9d38f91c removed port 2025-11-10 12:13:49 +00:00
00bb5748a2 Fix certificatesResolvers typo in Traefik static configuration
Changed 'certresolver' to 'certificatesResolvers' (plural) which is the correct
Traefik v3 configuration key for defining ACME certificate resolvers.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 11:41:14 +00:00
91220941b3 2025-11-10 11:38:32 +00:00
cebd955b3d 2025-11-10 11:34:56 +00:00
ea7a373bc4 Fix Traefik SSL certificate issues
- Fixed volume mount syntax for Swarm (use long-form bind mount syntax)
- Fixed Portainer TLS label syntax (tls.certresolver instead of tls.certificatesResolvers)
- These changes resolve SSL errors and certificate mounting issues

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 11:32:49 +00:00
3871e30abd Configure Traefik for public-facing access with frostlabs.me domains
- Fixed certificatesResolvers configuration in static.yml (moved out of tls section)
- Added DNS resolvers to Cloudflare ACME challenge configuration
- Added persistent volume mount for Let's Encrypt certificates
- Updated Outline service labels to use flow.frostlabs.me with proper cert resolver
- Updated Authentik service labels to use auth.frostlabs.me with proper cert resolver
- Added security headers and rate limiting middlewares to dynamic.yml
- Added example templates for public-facing service configuration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 11:27:47 +00:00
ad08678553 2025-11-10 05:45:12 -05:00
6d91de09bb 2025-11-10 05:33:48 -05:00
cf51fc562f 2025-11-10 05:30:33 -05:00
62b500eccd 2025-11-10 05:24:55 -05:00
eef5a0ade3 remove conf from gitignore 2025-11-10 10:23:05 +00:00
1772646148 released to the swarm 2025-11-08 23:45:01 +00:00
21900d13b7 placed rsync on p0 2025-11-08 23:26:28 +00:00
91ab6be16f fixed pinning issue 2025-11-08 16:54:51 +00:00
7cf52364bd pinned to node 2025-11-08 16:53:44 +00:00
58883a5639 update the port 2025-11-08 16:49:04 +00:00
e072b6b2e0 2025-11-08 10:54:48 +00:00
f89f7d18ec Fix MediaCMS static files by removing static volume mounts
- Removed static directory volume mounts from all services
- Static files now stay in container (generated during build)
- Only media_files directory is mounted for persistent storage
- This fixes the white screen issue caused by missing CSS/JS files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 01:04:37 +00:00
798e1ef370 Add MediaCMS stack configuration
- Created stack.yml for MediaCMS deployment
- Configured PostgreSQL, Redis, web, migrations, and Celery workers
- Set up proper volume mounts for media and static files
- Integrated with homelab network for Traefik routing
- Exposed web service on port 8880

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 01:00:53 +00:00
58c4fdc9c5 New Service: MediaCMS 2025-11-08 00:49:12 +00:00
2f3c4ce51b removed uptime service 2025-11-07 02:09:56 +00:00
33b72af6a0 updated readme to match current config 2025-11-07 02:09:41 +00:00
26 changed files with 545 additions and 248 deletions

View File

@@ -0,0 +1,43 @@
name: Deploy All Stacks to Swarm
on:
push:
branches:
- main
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Deploy remaining stacks
run: |
for stack_file in *-stack.yml; do
stack_name="${stack_file%-stack.yml}"
# Skip traefik, git-runner (deploy those manually)
if [[ "$stack_name" != "traefik" && "$stack_name" != "git-runner" ]]; then
echo "🚀 Deploying ${stack_name}..."
docker stack deploy -c "$stack_file" "$stack_name" --prune --with-registry-auth
fi
done
- name: Deploy remaining stacks
run: |
for stack_file in *-stack.yml; do
stack_name="${stack_file%-stack.yml}"
# Skip if already deployed
if [[ "$stack_name" != "traefik" && "$stack_name" != "git-runner" ]]; then
echo "🚀 Deploying ${stack_name}..."
docker stack deploy -c "$stack_file" "$stack_name" --prune --with-registry-auth
fi
done
- name: List deployed stacks
run: |
echo ""
echo "📋 All deployed stacks:"
docker stack ls

2
.gitignore vendored
View File

@@ -1 +1 @@
conf/
\conf\traefik-conf\cloudflre service token.txt

32
.vscode/setting.json vendored
View File

@@ -1,32 +0,0 @@
{
"files.associations": {
"*.yml": "yaml",
"*.yaml": "yaml",
"docker-compose*.yml": "yaml",
"stack.yml": "yaml"
},
"yaml.schemas": {
"https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json": [
"docker-compose*.yml",
"**/stacks/**/stack.yml"
]
},
"yaml.format.enable": true,
"yaml.validate": true,
"editor.formatOnSave": true,
"editor.rulers": [80, 120],
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
"git.autofetch": true,
"git.confirmSync": false,
"terminal.integrated.defaultProfile.windows": "PowerShell",
"[yaml]": {
"editor.insertSpaces": true,
"editor.tabSize": 2,
"editor.autoIndent": "advanced",
"editor.defaultFormatter": "redhat.vscode-yaml"
},
"[markdown]": {
"editor.defaultFormatter": "yzhang.markdown-all-in-one"
}
}

View File

@@ -16,6 +16,29 @@ All nodes are managers providing a 4-node quorum (can tolerate 2 node failures w
- **GlusterFS** mounted at `/home/doc/swarm-data/` on all nodes
- Shared storage enables services to run on any node without storage constraints
## Directory Structure
```
swarm/
├── conf/ # Traefik and service configurations
├── stacks/
│ ├── apps/ # Application services
│ │ ├── adminer/ # Database management
│ │ ├── n8n/ # Workflow automation
│ │ ├── outline/ # Documentation wiki
│ │ ├── paperless/ # Document management
│ │ └── uptime/ # Uptime monitoring
│ ├── core/ # Core infrastructure
│ │ ├── authentik/ # SSO/Authentication
│ │ ├── portainer/ # Container management
│ │ └── traefik/ # Reverse proxy
│ ├── data/ # Data services
│ │ └── rsync/ # Backup service
│ └── web/ # Web services
│ └── tracker/ # Tracker site
└── README.md
```
## Service Distribution Strategy
### Pinned Services
@@ -31,20 +54,36 @@ Services that can run on any node (swarm auto-balances):
- adminer
- authentik (server, worker, redis)
- n8n
- outline
- paperless (webserver, redis)
- tracker-nginx
- uptime-kuma
## Recent Changes (2025-10-30)
## Network Configuration
### Swarm Rebalancing
All services are connected to the `homelab` external overlay network for inter-service communication.
### Local Deployment (2025-11-07)
- Services now use `.swarm.home` domains for local access
- TLS enabled without external certificate resolvers
- Simplified Traefik configuration for local development
- Removed Cloudflare DNS integration
## Recent Changes
### Local Configuration Update (2025-11-07)
- Migrated from external `.frostlabs.me` domains to local `.swarm.home` domains
- Updated Traefik labels across all services for local deployment
- Simplified `.gitignore` to exclude entire `conf/` directory
- Moved Authentik from `apps/` to `core/` directory structure
- Removed Traefik labels from n8n and paperless for direct access
- Updated Traefik stack configuration for simplified port bindings
### Swarm Rebalancing (2025-10-30)
- Promoted p1, p2, p3 from workers to managers
- Removed unnecessary hostname constraints from service configs
- Force-redeployed services to redistribute across all nodes
- Verified GlusterFS accessibility on all nodes
### Results
- Achieved balanced workload distribution across all 4 nodes
- Improved high availability with 4-node manager quorum
- Services now self-balance automatically when nodes fail/recover
- Fixed Portainer agent connectivity by restarting agents after manager promotion
- Services now self-balance automatically when nodes fail/recover

View File

@@ -30,4 +30,4 @@ services:
- traefik.http.services.adminer.loadbalancer.server.port=8080
networks:
homelab:
external: true
external: true

View File

@@ -0,0 +1,3 @@
cloudflre service token=
CF-Access-Client-Id: dd8446c2a917e1f281a6f7e79c9171a9.access
CF-Access-Client-Secret: 7285e7b3b02510087774c06f52654c76932e8c83c758d9f3649dfe56a1d5385b

View File

@@ -0,0 +1,75 @@
# Traefik Dynamic Configuration for External Services
# This file handles routing to services NOT managed by Docker Swarm
http:
#-----------------------------------------------------------------------------------
# EXTERNAL SERVICES SECTION
#-----------------------------------------------------------------------------------
services:
unraid:
loadBalancer:
servers:
- url: "http://10.0.4.10:80"
# emby:
# loadBalancer:
# servers:
# - url: "http://10.0.4.10:8096"
# peertube:
# loadBalancer:
# servers:
# - url: "http://10.0.4.10:9000"
#-----------------------------------------------------------------------------------
# ROUTERS SECTION
#-----------------------------------------------------------------------------------
routers:
# Local VPN-only services (*.swarm.home)
unraid:
rule: "Host(`unraid.frostlabs.me`)"
entryPoints:
- websecure
service: unraid
middlewares:
- authentik
tls:
certResolver: cloudflare
# peertube:
# rule: "Host(`videos.frostlabs.me`)"
# entryPoints:
# - websecure
# service: peertube
# tls:
# certResolver: cloudflare
#-----------------------------------------------------------------------------------
# MIDDLEWARES SECTION
#-----------------------------------------------------------------------------------
middlewares:
# Authentik forward auth for protecting services
authentik:
forwardAuth:
address: "http://authentik_server:9000/outpost.goauthentik.io/auth/traefik"
trustForwardHeader: true
authResponseHeaders:
- X-authentik-username
- X-authentik-groups
- X-authentik-email
- X-authentik-name
- X-authentik-uid
# Security headers for public-facing services
security-headers:
headers:
frameDeny: true
browserXssFilter: true
contentTypeNosniff: true
sslRedirect: true
forceSTSHeader: true
stsSeconds: 31536000
stsIncludeSubdomains: true
stsPreload: true
# Rate limiting for public services
rate-limit:
rateLimit:
average: 100
period: 1s
burst: 50

View File

@@ -0,0 +1,59 @@
# /etc/traefik/traefik.yml or /etc/traefik/static.yml
# Global configuration
global:
checkNewVersion: false
sendAnonymousUsage: false
# API and Dashboard
api:
dashboard: true
insecure: true
# Health check endpoint
ping: {}
# Entry points
entryPoints:
web:
address: ":80"
http:
redirections:
entrypoint:
to: websecure
scheme: https
websecure:
address: ":443"
# Providers
providers:
# Docker Swarm provider
swarm:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: homelab
watch: true
# File provider for dynamic configuration
file:
directory: /etc/traefik/dynamic
watch: true
# Certificate resolvers
certificatesResolvers:
cloudflare:
acme:
email: john.allisonwin@outlook.com
storage: /certificates/acme.json
dnsChallenge:
provider: cloudflare
resolvers:
- 1.1.1.1:53
- 8.8.8.8:53
# Logging
log:
level: INFO
accessLog: {}

33
emby-stack.yml Normal file
View File

@@ -0,0 +1,33 @@
services:
emby:
image: lscr.io/linuxserver/emby:latest
networks:
- homelab
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
volumes:
- /home/doc/projects/swarm-data/appdata/emby:/config
- /home/doc/projects/data/media/tv:/data/tvshows
- /home/doc/projects/data/media/movies:/data/movies
ports:
- 8096:8096
healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost:8096/web/index.html" ]
interval: 30s
timeout: 10s
retries: 5
start_period: 120s
deploy:
replicas: 1
labels:
- traefik.enable=true
- traefik.http.routers.emby.rule=Host(`movies.frostlabs.me`)
- traefik.http.routers.emby.entrypoints=websecure
- traefik.http.routers.emby.tls=true
- traefik.http.routers.emby.tls.certresolver=cloudflare
- traefik.http.services.emby.loadbalancer.server.port=8096
networks:
homelab:
external: true

27
git-runner-stack.yml Normal file
View File

@@ -0,0 +1,27 @@
services:
gitea-runner:
image: gitea/act_runner:latest
hostname: "{{.Node.Hostname}}-runner"
environment:
- GITEA_INSTANCE_URL=https://git.frostlabs.me
- GITEA_RUNNER_REGISTRATION_TOKEN=hF9V6IIV4lj1cZVgNaZAXuXOcdVBiAQuoZdTU5Pp
- GITEA_RUNNER_NAME=swarm-runner-{{.Node.Hostname}}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- gitea-runner-data:/data
networks:
- homelab # Adjust to match your Gitea network
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
volumes:
gitea-runner-data:
networks:
homelab:
external: true

View File

@@ -3,6 +3,8 @@ services:
image: n8nio/n8n:latest
networks:
- homelab
ports:
- 5678:5678
environment:
- N8N_HOST=n8n.bitfrost.me
- N8N_PORT=5678
@@ -30,7 +32,14 @@ services:
memory: 2G
reservations:
memory: 512M
labels:
- traefik.enable=true
- traefik.http.routers.n8n.rule=Host(`n8n.bitfrost.me`)
- traefik.http.routers.n8n.entrypoints=websecure
- traefik.http.routers.n8n.tls=true
- traefik.http.routers.n8n.tls.certresolver=cloudflare
- traefik.http.services.n8n.loadbalancer.server.port=5678
networks:
homelab:
external: true
external: true

21
notifiarr-stack.yml Normal file
View File

@@ -0,0 +1,21 @@
services:
notifiarr:
image: golift/notifiarr:latest
hostname: notifiarr
networks:
- homelab
ports:
- "5454:5454"
volumes:
- /home/doc/projects/swarm-data/appdata/Notifiarr:/config
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- TZ=America/New_York
- PUID=1000
- PGID=1000
deploy:
replicas: 1
networks:
homelab:
external: true

View File

@@ -40,9 +40,11 @@ services:
labels:
- "traefik.enable=true"
- "traefik.swarm.network=homelab"
- "traefik.http.routers.outline.rule=Host(`flow.swarm.home`)"
# Public-facing domain with Let's Encrypt certificate
- "traefik.http.routers.outline.rule=Host(`flow.frostlabs.me`)"
- "traefik.http.routers.outline.entrypoints=websecure"
- "traefik.http.routers.outline.tls=true"
- "traefik.http.routers.outline.tls.certresolver=cloudflare"
- "traefik.http.services.outline.loadbalancer.server.port=3000"
depends_on:
- redis
@@ -77,4 +79,4 @@ networks:
external: true
outline_internal:
driver: overlay
attachable: true
attachable: true

View File

@@ -79,4 +79,4 @@ secrets:
paperless-secret-key:
external: true
postgres-master:
external: true
external: true

108
peertube-stack.yml Normal file
View File

@@ -0,0 +1,108 @@
services:
peertube:
image: chocobozzz/peertube:production-bookworm
networks:
- homelab
environment:
# Database configuration - connecting to existing Postgres
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=AllOfTheStars+1
- POSTGRES_DB=peertube
- POSTGRES_HOSTNAME=postgres
- POSTGRES_PORT=5432
- PEERTUBE_DB_HOSTNAME=postgres
- PEERTUBE_DB_PORT=5432
- PEERTUBE_DB_USERNAME=admin
- PEERTUBE_DB_PASSWORD=AllOfTheStars+1
- PEERTUBE_DB_NAME=peertube
# Redis configuration
- REDIS_HOSTNAME=redis
- PEERTUBE_REDIS_HOSTNAME=redis
# PeerTube configuration
- PEERTUBE_WEBSERVER_HOSTNAME=videos.frostlabs.me
- PEERTUBE_WEBSERVER_PORT=443
- PEERTUBE_WEBSERVER_HTTPS=true
- PEERTUBE_TRUST_PROXY=["127.0.0.1", "loopback", "10.0.1.0/24"]
# SMTP configuration - Gmail
- PEERTUBE_SMTP_HOSTNAME=smtp.gmail.com
- PEERTUBE_SMTP_PORT=587
- PEERTUBE_SMTP_USERNAME=frostlabs25@gmail.com
- PEERTUBE_SMTP_PASSWORD=tewo awqe ffhw rtun
- PEERTUBE_SMTP_FROM=frostlabs25@gmail.com
- PEERTUBE_SMTP_TLS=true
- PEERTUBE_SMTP_DISABLE_STARTTLS=false
- PEERTUBE_ADMIN_EMAIL=frostlabs25@gmail.com
# Secrets - loaded from Docker secrets as files
- PEERTUBE_SECRET=dfd1cad851c1a5b795131fd2033d46ef80c809b5ac30a3ce8e69b049587138a2
# secrets:
# - postgres-master
# - peertube-key
# - gmail-app-password
# ports:
# - target: 9000
# published: 9000
# mode: host
# - target: 1935
# published: 1935
# mode: host
volumes:
# - /home/doc/projects/swarm-data/appdata/peertube/assets:/app/client/dist
- /home/doc/projects/swarm-data/appdata/peertube/data:/data
# healthcheck:
# test: [ "CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:9000/api/v1/config" ]
# interval: 30s
# timeout: 10s
# retries: 3
# start_period: 60s
deploy:
mode: replicated
replicas: 1
labels:
- traefik.enable=true
- traefik.http.routers.peertube.rule=Host(`videos.frostlabs.me`)
- traefik.http.routers.peertube.entrypoints=websecure
- traefik.http.routers.peertube.tls=true
- traefik.http.routers.peertube.tls.certresolver=cloudflare
- traefik.http.services.peertube.loadbalancer.server.port=9000
redis:
image: redis:7-alpine
networks:
- homelab
volumes:
- /home/doc/projects/swarm-data/appdata/peertube/redis:/data
healthcheck:
test: [ "CMD", "redis-cli", "ping" ]
interval: 30s
timeout: 5s
retries: 3
deploy:
mode: replicated
replicas: 1
postgres:
image: postgres:17-alpine
networks:
- homelab
environment:
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=AllOfTheStars+1
- POSTGRES_DB=peertube
volumes:
- /home/doc/projects/swarm-data/appdata/peertube/postgres:/var/lib/postgresql/data
ports:
- 5432:5432
deploy:
replicas: 1
networks:
homelab:
external: true
# secrets:
# postgres-master:
# external: true
# peertube-key:
# external: true
# gmail-app-password:
# external: true

25
prowlarr-stack.yml Normal file
View File

@@ -0,0 +1,25 @@
services:
prowlarr:
image: lscr.io/linuxserver/prowlarr:latest
networks:
- homelab
ports:
- 9696:9696
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
volumes:
- /home/doc/projects/swarm-data/appdata/prowlarr:/config
healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost:9696/ping" ]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
replicas: 1
networks:
homelab:
external: true

0
pulse-stack.yml Normal file
View File

26
radarr-stack.yml Normal file
View File

@@ -0,0 +1,26 @@
services:
radarr:
image: lscr.io/linuxserver/radarr:latest
networks:
- homelab
ports:
- 7878:7878
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
volumes:
- /home/doc/projects/swarm-data/appdata/radarr:/config
- /home/doc/projects/data:/data
healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost:7878/ping" ]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
replicas: 1
networks:
homelab:
external: true

26
sab-stack.yml Normal file
View File

@@ -0,0 +1,26 @@
services:
sabnzbd:
image: lscr.io/linuxserver/sabnzbd:latest
networks:
- homelab
ports:
- 8080:8080
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
volumes:
- /home/doc/projects/swarm-data/appdata/sabnzbd:/config
- /home/doc/projects/data/usenet:/data/usenet
healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost:8080/api?mode=version" ]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
replicas: 1
networks:
homelab:
external: true

20
sonarr-stack.yml Normal file
View File

@@ -0,0 +1,20 @@
services:
sonarr:
image: lscr.io/linuxserver/sonarr:latest
networks:
- homelab
ports:
- 8989:8989
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
volumes:
- /home/doc/projects/swarm-data/appdata/sonarr:/config
- /home/doc/projects/data:/data
deploy:
replicas: 1
networks:
homelab:
external: true

View File

@@ -1,28 +0,0 @@
services:
uptime-kuma:
image: louislam/uptime-kuma:1.23.16
volumes:
- /home/doc/projects/swarm-data/appdata/uptime:/app/data
environment:
- TZ=America/New_York
networks:
- homelab
healthcheck:
test: [ "CMD", "node", "/app/extra/healthcheck.js" ]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
replicas: 1
labels:
- "traefik.enable=true"
- "traefik.swarm.network=homelab"
- "traefik.http.routers.uptime-kuma.rule=Host(`status.swarm.home)"
- "traefik.http.routers.uptime-kuma.entrypoints=web,websecure"
- "traefik.http.routers.uptime-kuma.tls=true
- "traefik.http.services.uptime-kuma.loadbalancer.server.port=3001"
networks:
homelab:
external: true

View File

@@ -1,112 +0,0 @@
services:
redis:
image: redis:alpine
command: --save 60 1 --loglevel warning
volumes:
- /home/doc/projects/swarm-data/appdata/authentik/redis:/data
ports:
- 6379:6379
networks:
- homelab
healthcheck:
test: [ "CMD", "redis-cli", "ping" ]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
deploy:
replicas: 1
resources:
limits:
memory: 512M
reservations:
memory: 128M
authentik_server:
image: ghcr.io/goauthentik/server:2025.10.0
command: server
environment:
AUTHENTIK_SECRET_KEY: "file:///run/secrets/auth-key"
AUTHENTIK_REDIS__HOST: "redis"
AUTHENTIK_POSTGRESQL__HOST: "10.0.4.10"
AUTHENTIK_POSTGRESQL__PORT: "5432"
AUTHENTIK_POSTGRESQL__USER: "admin"
AUTHENTIK_POSTGRESQL__NAME: "authentik"
AUTHENTIK_POSTGRESQL__PASSWORD: "file:///run/secrets/postgres-master"
# Optional: Set error reporting (set to false for privacy)
AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
secrets:
- auth-key
- postgres-master
volumes:
- /home/doc/projects/swarm-data/appdata/authentik/media:/media
- /home/doc/projects/swarm-data/appdata/authentik/templates:/templates
- /var/run/docker.sock:/var/run/docker.sock
networks:
- homelab
healthcheck:
test: [ "CMD-SHELL", "ak healthcheck" ]
interval: 30s
timeout: 10s
retries: 3
start_period: 90s
deploy:
replicas: 1
resources:
limits:
memory: 1G
cpus: '1.0'
reservations:
memory: 512M
labels:
- "traefik.enable=true"
- "traefik.swarm.network=homelab"
- "traefik.http.routers.authentik.rule=Host(`auth.swam.home`)"
- "traefik.http.routers.authentik.entrypoints=web,websecure"
- "traefik.http.routers.authentik.tls=true"
- "traefik.http.services.authentik.loadbalancer.server.port=9000"
depends_on:
- redis
authentik_worker:
image: ghcr.io/goauthentik/server:2025.10.0
command: worker
environment:
AUTHENTIK_SECRET_KEY: "file:///run/secrets/auth-key"
AUTHENTIK_REDIS__HOST: "redis"
AUTHENTIK_POSTGRESQL__HOST: "10.0.4.10"
AUTHENTIK_POSTGRESQL__PORT: "5432"
AUTHENTIK_POSTGRESQL__USER: "admin"
AUTHENTIK_POSTGRESQL__NAME: "authentik"
AUTHENTIK_POSTGRESQL__PASSWORD: "file:///run/secrets/postgres-master"
# Optional: Set error reporting (set to false for privacy)
AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
secrets:
- auth-key
- postgres-master
volumes:
- /home/doc/projects/swarm-data/appdata/authentik/media:/media
- /home/doc/projects/swarm-data/appdata/authentik/templates:/templates
- /var/run/docker.sock:/var/run/docker.sock
networks:
- homelab
deploy:
replicas: 1
resources:
limits:
memory: 1G
cpus: '1.0'
reservations:
memory: 512M
depends_on:
- redis
networks:
homelab:
external: true
secrets:
postgres-master:
external: true
auth-key:
external: true

View File

@@ -1,37 +0,0 @@
services:
portainer:
image: portainer/portainer-ce:latest
command: -H tcp://tasks.agent:9001 --tlsskipverify
volumes:
- /home/doc/projects/swarm-data/appdata/portainer:/data
networks:
- homelab
ports:
- 9000:9000
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.hostname == p0
labels:
- "traefik.enable=true"
- "traefik.swarm.network=homelab"
- "traefik.http.routers.portainer.rule=Host(`portainer.swarm.home`)"
- "traefik.http.routers.portainer.entrypoints=web,websecure"
- "traefik.http.routers.portainer.tls=true"
- "traefik.http.services.portainer.loadbalancer.server.port=9000"
agent:
image: portainer/agent:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/volumes:/var/lib/docker/volumes
networks:
- homelab
deploy:
mode: global
networks:
homelab:
external: true

View File

@@ -1,20 +0,0 @@
services:
rsync:
image: alpine:latest
user: "0:0"
command: >
sh -c " apk add --no-cache rsync && echo '0 2 * * * rsync -av --no-perms --no-owner --no-group --exclude-from=/excludes.txt /source/ /destination/ && echo \"Sync completed at $$(date)\"' | crontab - && echo 'Backup sync started. Daily sync at 2 AM.' && crond -f -l 2"
deploy:
replicas: 1
restart_policy:
condition: on-failure
delay: 30s
volumes:
- /home/doc/projects/swarm-data/appdata:/source:ro
- /home/doc/projects/backups:/destination
- /home/doc/projects/swarm/conf/rsync-conf/excludes.txt:/excludes.txt:ro
networks:
- homelab
networks:
homelab:
external: true

View File

@@ -5,14 +5,24 @@ services:
ports:
- 80:80
- 443:443
- 8080:8080
- 8082:8080
environment:
- CF_DNS_API_TOKEN_FILE=/run/secrets/cloudflare_api_token
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
#
- /home/doc/projects/swarm/conf/traefik-conf/static.yml:/etc/traefik/traefik.yml:ro
- /home/doc/projects/swarm/conf/traefik-conf/dynamic.yml:/etc/traefik/dynamic/dynamic.yml:rw
- type: bind
source: /var/run/docker.sock
target: /var/run/docker.sock
read_only: true
- type: bind
source: /home/doc/projects/swarm-data/swarm-production/conf/traefik-conf/static.yml
target: /etc/traefik/traefik.yml
read_only: true
- type: bind
source: /home/doc/projects/swarm-data/swarm-production/conf/traefik-conf/dynamic.yml
target: /etc/traefik/dynamic/dynamic.yml
- type: bind
source: /home/doc/projects/swarm-data/appdata/traefik/certificates/acme.json
target: /certificates/acme.json
secrets:
- cloudflare_api_token
networks:
@@ -28,7 +38,7 @@ services:
replicas: 1
placement:
constraints:
- node.hostname == p0
- node.hostname == p0
networks:
homelab:
@@ -36,4 +46,4 @@ networks:
secrets:
cloudflare_api_token:
external: true
external: true