Compare commits

..

139 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
dac81b1220 more more changes 2025-11-07 01:59:13 +00:00
f35fc3831c more changes 2025-11-07 01:57:24 +00:00
9e00080313 Updated swarm deploy config 2025-11-07 01:56:07 +00:00
c5b0c67ca7 Refactor Docker Swarm stack configurations for local deployment
Updated multiple stack files to use local hostnames instead of external domains, simplified Traefik configuration, and reorganized Authentik service location. Changes improve local development setup and reduce complexity.

Key changes:
- Simplified .gitignore to exclude entire conf/ directory
- Updated Traefik labels across services to use .swarm.home domains
- Removed Cloudflare cert resolver references for local TLS
- Moved Authentik from apps/ to core/ directory structure
- Removed Traefik labels from n8n and paperless services
- Updated Traefik stack to use simplified port bindings
- Added timezone environment variable to adminer and outline

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 01:38:48 +00:00
bc67ba5341 Delete conf/traefik-conf/.nfs002e00000006163d00000001 2025-11-06 20:25:24 +00:00
fcf5751b70 updated traefik config 2025-11-06 20:24:42 +00:00
c87db2c40b removed exposed port 2025-11-06 10:43:04 +00:00
c6829ada57 fixed port 2025-11-05 22:56:52 +00:00
73e0a611a7 updated traefik config 2025-11-05 22:54:30 +00:00
89b6ea0b35 updated traefik config 2025-11-05 22:51:00 +00:00
2b9f142b7a updated traefik configurations 2025-11-05 22:47:01 +00:00
a070f44d87 proxy n8n through traefik 2025-11-05 22:36:52 +00:00
2af45d5ef8 removed cli arguments from traefik config in favor of stactic.yml file. added the static.yml to gitignore for privacy 2025-11-05 22:22:57 +00:00
f02c9eaf26 updated mount config 2025-11-05 21:57:17 +00:00
feae85b159 updates 2025-11-05 20:11:08 +00:00
bd6b6e5b0e update file provider 2025-11-05 19:34:52 +00:00
33918e07d4 Disable traefik temporarily 2025-11-05 19:16:17 +00:00
1e5c2a0f19 testing new port 2025-11-04 19:58:51 +00:00
e3b65213c1 addded nginx-pm 2025-11-04 19:47:06 +00:00
94ca2a9be8 rm traefik-local 2025-11-04 19:21:55 +00:00
4ee8b16b8b updated portainer 2025-11-04 17:23:36 +00:00
d8b3b2edc9 Updated traefik labels 2025-11-04 17:23:23 +00:00
8e3867b4c3 added service adguard 2025-11-04 16:21:14 +00:00
2b62dfe96a Removed service 2025-11-04 13:18:53 +00:00
7de1d40a51 Removed Service 2025-11-04 13:18:51 +00:00
ac647ed02a Move Paperless to local Traefik with HTTPS
- Remove port 8011 binding, route through Traefik instead
- Add Traefik labels for docs.home.frostlabs.me
- Update Paperless URLs to use HTTPS with local domain
- Configure allowed hosts and CSRF trusted origins

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 02:48:08 +00:00
dfd5295d88 Fix remaining volume mount paths in stack configs
- Update Vikunja config path to remove swarm-production subdirectory
- Fix rsync source path to backup appdata instead of backups directory
- Update rsync excludes path to correct location in projects directory

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 22:57:48 +00:00
ffb307a1eb Updated paths again 2025-11-03 22:27:40 +00:00
795cdd8a05 Updated mounts using new paths 2025-11-03 22:26:07 +00:00
a1af5b4c9b Update paths and configurations for swarm infrastructure
- Update all volume paths from /home/doc/swarm-data to /home/doc/projects/swarm-data
- Add Traefik local entrypoint on port 8443 with host mode networking
- Add Adminer local route with Traefik labels
- Configure Vikunja OIDC integration with Authentik
- Add Outline stack configuration
- Add traefik-local stack for local network routing
- Update .gitignore with backup files and dynamic configs

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 22:12:17 +00:00
b6ae643c39 2025-11-02 19:20:04 +00:00
b4f17e5d76 2025-11-02 19:19:51 +00:00
b62b890482 Add healthchecks and resource constraints to all services
Added healthchecks:
- adminer: PHP file_get_contents check
- authentik_server: ak healthcheck command
- authentik_redis: redis-cli ping
- paperless_redis: redis-cli ping
- paperless_webserver: curl localhost:8000
- n8n: wget healthz endpoint
- traefik: wget ping endpoint (with --ping enabled)
- tracker-nginx: curl localhost:80

Added resource limits:
- adminer: 512M limit, 128M reservation
- authentik_server: 1G/1 CPU limit, 512M reservation
- authentik_worker: 1G/1 CPU limit, 512M reservation
- authentik_redis: 512M limit, 128M reservation
- paperless_redis: 512M limit, 128M reservation
- paperless_webserver: 2G/2 CPU limit, 1G reservation
- traefik: 512M/0.5 CPU limit, 256M reservation
- tracker-nginx: 256M limit, 64M reservation

All services now have proper health monitoring and resource constraints
to prevent resource exhaustion and improve reliability.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 09:08:49 +00:00
dde99083fb Rebalance swarm: promote all nodes to managers and remove hostname constraints
- Promoted p1, p2, p3 from worker to manager nodes for 4-node quorum
- Removed unnecessary hostname constraints from service configs
- Only traefik and portainer remain pinned to p0
- Services now auto-balance across all nodes via GlusterFS shared storage
- Updated README with cluster overview and distribution strategy

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 08:52:38 +00:00
8eb3106777 Add Authentik SSO service with fixed service dependencies
Adds new Authentik (v2025.10.0) authentication/SSO stack with:
- Redis cache service
- Authentik server (exposed at auth.frostlabs.me via Traefik)
- Authentik worker for background tasks
- Fixed depends_on references to use correct service name (redis)
- External PostgreSQL backend at 10.0.4.10
- Docker secrets integration for sensitive credentials

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-29 16:51:47 +00:00
ffd76f7fa8 Update rsync destination volume path in stack.yml 2025-10-28 22:16:41 +00:00
e5513e9358 Remove FreeFileSync and nginx service configurations from stack.yml 2025-10-28 00:39:50 +00:00
717d3a87d0 Reduce tracker-nginx replicas from 3 to 1 for optimized resource usage 2025-10-28 00:39:40 +00:00
ed60abf96f launched service: rysnc w/ excludes.txt 2025-10-28 00:39:30 +00:00
51a7aae379 Refactor environment variables in stack.yml: removed http:// from DBHOST and eliminated postgres dependency 2025-10-27 21:46:31 +00:00
8ec72187a4 Redeploy using N8N Workflow 2025-10-27 18:02:48 +00:00
3ddbe69470 trying to fix mnt permissions 2025-10-27 16:57:07 +00:00
b8f0bd95f0 adminer 2025-10-27 16:39:23 +00:00
7395ce218b adminer 2025-10-27 16:37:18 +00:00
6c30b34617 adminer 2025-10-27 16:36:43 +00:00
43dba6b06d adminer 2025-10-27 16:25:36 +00:00
9d02d258f8 adminer 2025-10-27 16:24:48 +00:00
c9824da5f6 tesst 2025-10-27 16:09:17 +00:00
9fa3af5617 ♻️ add uptime-kuma service configuration to stack 2025-10-27 15:09:50 +00:00
3a35817ea0 ♻️ update volume path for n8n service in stack configuration 2025-10-27 11:23:12 +00:00
0d2143c24d ♻️ update volume paths in tracker service configuration 2025-10-27 11:17:37 +00:00
121452cb3f ⬇️ Replicas 2 ---> 1 2025-10-27 11:09:26 +00:00
44350ba5be Test Push 2025-10-27 11:08:24 +00:00
10fea7025c ⬆️ replicas 1 ---> 2 2025-10-27 11:06:46 +00:00
69e06b8b6c ♻️ update Traefik configuration for Portainer service and remove exposed ports 2025-10-27 11:01:44 +00:00
f6dcf8f65f add FreeFileSync service configuration to stack 2025-10-27 09:40:06 +00:00
b79b685da4 ♻️ update volume paths for Traefik service in stack configuration 2025-10-27 09:40:02 +00:00
c6a5cd523d 🚫 remove PostgreSQL service configuration from stack 2025-10-27 09:39:54 +00:00
5036603613 🚀 add Portainer and agent services to stack configuration 2025-10-27 09:39:10 +00:00
e3c7475aa8 add .gitignore to exclude dynamic.yml configuration file 2025-10-27 09:39:03 +00:00
29 changed files with 834 additions and 231 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

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
\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

@@ -1,3 +1,89 @@
# swarm-production
Production Docker Swarm Infrastructure
Production Docker Swarm Infrastructure
## Cluster Overview
### Nodes
- **p0** (Manager/Leader) - Infrastructure services
- **p1** (Manager) - Application services
- **p2** (Manager) - Application services
- **p3** (Manager) - Application services
All nodes are managers providing a 4-node quorum (can tolerate 2 node failures while maintaining quorum).
### Storage
- **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
Services that must run on specific nodes:
- **traefik** (p0) - Published ports 80/443, needs stable IP for DNS
- **portainer** (p0) - Management UI, stays with leader for convenience
- **rsync** (manager constraint) - Backup service, needs manager access
### Floating Services
Services that can run on any node (swarm auto-balances):
- adminer
- authentik (server, worker, redis)
- n8n
- outline
- paperless (webserver, redis)
- tracker-nginx
- uptime-kuma
## Network Configuration
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
- 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

33
adminer-stack.yml Normal file
View File

@@ -0,0 +1,33 @@
services:
adminer:
image: adminer:latest
networks:
- homelab
environment:
- ADMINER_DEFAULT_SERVER=10.0.4.10
- ADMINER_DESIGN=nette
- TZ=America/New_York
healthcheck:
test: [ "CMD", "php", "-r", "if (file_get_contents('http://localhost:8080')) exit(0); exit(1);" ]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
deploy:
replicas: 1
resources:
limits:
memory: 512M
reservations:
memory: 128M
labels:
# Local route
- traefik.enable=true
- traefik.swarm.network=homelab
- traefik.http.routers.adminer.rule=Host(`miner.swarm.home`)
- traefik.http.routers.adminer.entrypoints=web,websecure
- traefik.http.routers.adminer.tls=true
- traefik.http.services.adminer.loadbalancer.server.port=8080
networks:
homelab:
external: true

View File

@@ -0,0 +1,7 @@
*.tmp
*.log
cache/
temp/
*.lock
lost+found/
traefik/certificates/acme.json

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

45
n8n-stack.yml Normal file
View File

@@ -0,0 +1,45 @@
services:
n8n:
image: n8nio/n8n:latest
networks:
- homelab
ports:
- 5678:5678
environment:
- N8N_HOST=n8n.bitfrost.me
- N8N_PORT=5678
- N8N_PROTOCOL=https
- N8N_RUNNERS_ENABLED=true
- WEBHOOK_URL=https://n8n.bitfrost.me/
- TZ=America/New_York
volumes:
- /home/doc/projects/swarm-data/appdata/n8n:/home/node/.n8n
- /var/run/docker.sock:/var/run/docker.sock:ro
healthcheck:
test: [ "CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:5678/healthz" ]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
replicas: 1
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
resources:
limits:
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

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

82
outline-stack.yml Normal file
View File

@@ -0,0 +1,82 @@
services:
outline:
image: outlinewiki/outline:latest
environment:
- PGSSLMODE=disable
- SECRET_KEY=2821b95392ba4ead8acb1882653eb217545ee267099608dee92ecde2cf9a7323
- UTILS_SECRET=cd5dab7c54b92603ba44bcab8a49e5a0f816b11a5b75ef25fe73ebb13633cae4
- DATABASE_URL=postgres://admin:AllOfTheStars%2B1@10.0.4.10:5432/outline
- REDIS_URL=redis://redis:6379
- URL=https://flow.frostlabs.me
- TZ=America/New_York
- PORT=3000
- FILE_STORAGE=local
- FILE_STORAGE_LOCAL_ROOT_DIR=/var/lib/outline/data
- FILE_STORAGE_UPLOAD_MAX_SIZE=26214400
# OIDC/SSO Configuration for Authentik
- OIDC_CLIENT_ID=9zCd8wzJFBv3oRYmdJXKWVokI0P3dx0HhuJB2yST
- OIDC_CLIENT_SECRET=fQpA7KFeDO2x8HKcQ5lOKFvB4HqyXcUvwUpow20bIOUBEZqoZ5hekkYS2kJ7BR2XayrOevq1sd4cC7Nw3mO1xz2jFXw0CiuhfNQTdMF35Zz2IXKbsNvVHU0Z1hYFjhlG
- OIDC_AUTH_URI=https://auth.frostlabs.me/application/o/authorize/
- OIDC_TOKEN_URI=https://auth.frostlabs.me/application/o/token/
- OIDC_USERINFO_URI=https://auth.frostlabs.me/application/o/userinfo/
- OIDC_LOGOUT_URI=https://auth.frostlabs.me/application/o/outline/end-session/
- OIDC_USERNAME_CLAIM=preferred_username
- OIDC_DISPLAY_NAME=Authentik
- OIDC_SCOPES=openid profile email
volumes:
- /home/doc/projects/swarm-data/appdata/outline/data:/var/lib/outline/data
networks:
- homelab
deploy:
replicas: 1
restart_policy:
condition: any
resources:
limits:
memory: 1G
cpus: '1.0'
reservations:
memory: 512M
labels:
- "traefik.enable=true"
- "traefik.swarm.network=homelab"
# 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
redis:
image: redis:7-alpine
volumes:
- /home/doc/projects/swarm-data/appdata/outline/redis:/data
networks:
- homelab
deploy:
replicas: 1
placement:
constraints:
- node.hostname == p0
restart_policy:
condition: on-failure
delay: 5s
resources:
limits:
memory: 256M
reservations:
memory: 128M
healthcheck:
test: [ "CMD", "redis-cli", "ping" ]
interval: 10s
timeout: 3s
retries: 3
networks:
homelab:
external: true
outline_internal:
driver: overlay
attachable: true

View File

@@ -3,37 +3,45 @@ services:
image: redis:alpine
networks:
- homelab
healthcheck:
test: [ "CMD", "redis-cli", "ping" ]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
deploy:
replicas: 1
placement:
constraints:
- node.hostname == p0
resources:
limits:
memory: 512M
reservations:
memory: 128M
paperless_webserver:
image: ghcr.io/paperless-ngx/paperless-ngx:latest
ports:
- 8000:8000
volumes:
- /home/doc/swarm/data/paperless/data:/usr/src/paperless/data
- /home/doc/swarm/data/paperless/media:/usr/src/paperless/media
- /home/doc/swarm/data/paperless/export:/usr/src/paperless/export
- /home/doc/swarm/data/paperless/consume:/usr/src/paperless/consume
- /home/doc/projects/swarm-data/appdata/paperless/data:/usr/src/paperless/data
- /home/doc/projects/swarm-data/appdata/paperless/media:/usr/src/paperless/media
- /home/doc/projects/swarm-data/appdata/paperless/export:/usr/src/paperless/export
- /home/doc/projects/swarm-data/appdata/paperless/consume:/usr/src/paperless/consume
secrets:
- postgres-master
- paperless-secret-key
- paperless-admin-pass
environment:
- PAPERLESS_DBPASS_FILE=/run/secrets/postgres-master
- PAPERLESS_SECRET_KEY_FILE=/run/secrets/paperless-secret-key
- PAPERLESS_ADMIN_PASSWORD_FILE=/run/secrets/paperless-admin-pass
- PAPERLESS_URLS=https://docs.frostlabs.me
- PAPERLESS_ALLOWED_HOSTS=docs.frostlabs.me
- PAPERLESS_CSRF_TRUSTED_ORIGINS=https://docs.frostlabs.me
- PAPERLESS_REDIS=redis://paperless_redis:6379
- PAPERLESS_DBHOST=http://10.0.4.10
- PAPERLESS_DBHOST=10.0.4.10
- PAPERLESS_DBPORT=5432
- PAPERLESS_DBNAME=paperless
- PAPERLESS_DBUSER=admin
- PAPERLESS_DBPASS_FILE=/run/secrets/postgres-master
- PAPERLESS_SECRET_KEY_FILE=/run/secrets/paperless-secret-key
- PAPERLESS_TIME_ZONE=America/New_York
- PAPERLESS_OCR_LANGUAGE=eng
- PAPERLESS_URLS=https://docs.frostlabs.home
- PAPERLESS_ALLOWED_HOSTS=docs.frostlabs.home
- PAPERLESS_CONSUMER_POLLING=5
- PAPERLESS_CONSUMER_DELETE_DUPLICATES=true
- PAPERLESS_CONSUMER_RECURSIVE=true
@@ -41,25 +49,34 @@ services:
- PAPERLESS_CONSUMER_IGNORE_PATTERNS=[".DS_Store","._*",".stfolder",".stversions","Thumbs.db"]
- PAPERLESS_ENABLE_CLASSIFIER=true
- PAPERLESS_ADMIN_USER=admin
- PAPERLESS_ADMIN_PASSWORD_FILE=/run/secrets/paperless-admin-pass
- PAPERLESS_ADMIN_MAIL=john.allisonwin@outlook.com
networks:
- homelab
healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost:8000" ]
interval: 30s
timeout: 10s
retries: 3
start_period: 90s
deploy:
replicas: 1
placement:
constraints:
- node.hostname == p0
resources:
limits:
memory: 2G
cpus: '2.0'
reservations:
memory: 1G
depends_on:
- postgres
- paperless_redis
networks:
homelab:
external: true
secrets:
paperless-admin-pass:
external: true
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,18 +0,0 @@
services:
adminer:
image: adminer:latest
networks:
- homelab
ports:
- 8091:8080
environment:
- ADMINER_DEFAULT_SERVER=10.0.4.10
- ADMINER_DESIGN=nette
deploy:
replicas: 1
placement:
constraints:
- node.hostname == p0
networks:
homelab:
external: true

View File

@@ -1,35 +0,0 @@
services:
n8n:
image: n8nio/n8n:latest
ports:
- 5678:5678
networks:
- homelab
environment:
- N8N_HOST=n8n.bitfrost.me
- N8N_PORT=5678
- N8N_PROTOCOL=https
- N8N_RUNNERS_ENABLED=true
- WEBHOOK_URL=https://n8n.bitfrost.me/
- TZ=America/New_York
volumes:
- /home/doc/swarm/data/n8n:/home/node/.n8n
- /var/run/docker.sock:/var/run/docker.sock:ro
deploy:
replicas: 1
placement:
constraints:
- node.hostname == p0
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
resources:
limits:
memory: 2G
reservations:
memory: 512M
networks:
homelab:
external: true

View File

@@ -1,27 +0,0 @@
services:
postgres:
image: postgres:17-alpine
secrets:
- postgres-master
networks:
- homelab
environment:
- POSTGRES_USER=admin
- POSTGRES_PASSWORD_FILE=/run/secrets/postgres-master
- PGDATA=/var/lib/postgresql/data
volumes:
- /home/doc/swarm/data/postgres:/var/lib/postgresql/data
ports:
- 5432:5432
deploy:
replicas: 1
placement:
constraints:
- node.hostname == p0
networks:
homelab:
external: true
secrets:
postgres-master:
external: true

View File

@@ -1,57 +0,0 @@
services:
traefik:
image: traefik:v3.5
command:
- --api.dashboard=true
- --api.insecure=true
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- --providers.swarm=true
- --providers.swarm.exposedByDefault=false
- --providers.swarm.network=homelab
- --providers.swarm.watch=true
- --providers.file.directory=/etc/traefik/dynamic
- --providers.file.watch=true
- --certificatesresolvers.cloudflare.acme.dnschallenge=true
- --certificatesresolvers.cloudflare.acme.dnschallenge.provider=cloudflare
- --certificatesresolvers.cloudflare.acme.email=john.allisonwin@outlook.com
- --certificatesresolvers.cloudflare.acme.storage=/certificates/acme.json
- --log.level=DEBUG
- --accesslog=true
ports:
- "80:80"
- "443:443"
- "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/swarm/data/traefik/certificates:/certificates
- /home/doc/swarm/conf/traefik-conf/dynamic.yml:/etc/traefik/dynamic/dynamic.yml:ro
secrets:
- cloudflare_api_token
networks:
- homelab
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.hostname == p0
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`proxy.frostlabs.me`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls.certresolver=cloudflare"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.services.traefik.loadbalancer.server.port=8080"
networks:
homelab:
external: true
secrets:
cloudflare_api_token:
external: true

View File

@@ -1,22 +0,0 @@
services:
nginx:
image: nginx:alpine
hostname: nginx
networks:
- caddy
ports:
- target: 80
published: 8080
mode: host
deploy:
replicas: 1
labels:
caddy: test.frostlabs.me
caddy.reverse_proxy: "nginx:80"
caddy.tls.dns: cloudflare
restart_policy:
condition: on-failure
networks:
caddy:
external: true

View File

@@ -1,19 +0,0 @@
services:
tracker-nginx:
image: nginx:alpine
ports:
- 8180:80
networks:
- homelab
volumes:
- /mnt/swarm-data/webservers/production/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- /mnt/swarm-data/webservers/production/nginx/.conf/default.conf:/etc/nginx/conf.d/default.conf:ro
- /mnt/swarm-data/webfiles/production/taylors-development:/usr/share/nginx/html:ro
deploy:
replicas: 3
placement:
constraints:
- node.role == worker
networks:
homelab:
external: true

27
tracker-stack.yml Normal file
View File

@@ -0,0 +1,27 @@
services:
tracker-nginx:
image: nginx:alpine
ports:
- 8180:80
networks:
- homelab
volumes:
- /home/doc/projects/swarm-data/appdata/webservers/production/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- /home/doc/projects/swarm-data/appdata/webservers/production/nginx/.conf/default.conf:/etc/nginx/conf.d/default.conf:ro
- /home/doc/projects/swarm-data/appdata/webfiles/production/taylors-development:/usr/share/nginx/html:ro
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:80 || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
deploy:
replicas: 1
resources:
limits:
memory: 256M
reservations:
memory: 64M
networks:
homelab:
external: true

49
traefik-stack.yml Normal file
View File

@@ -0,0 +1,49 @@
services:
traefik:
image: traefik:v3.5.4
# Remove all command arguments - using static config file instead
ports:
- 80:80
- 443:443
- 8082:8080
environment:
- CF_DNS_API_TOKEN_FILE=/run/secrets/cloudflare_api_token
volumes:
- 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:
- homelab
healthcheck:
test: [ "CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/ping" ]
interval: 30s
timeout: 5s
retries: 3
start_period: 30s
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.hostname == p0
networks:
homelab:
external: true
secrets:
cloudflare_api_token:
external: true