diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index ef961f8..fb0c615 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -32,8 +32,8 @@ updates:
- "/docker/personal/syncthing"
- "/docker/personal/tandoor"
- "/docker/production/alexscript"
- - "/docker/production/semery.fr"
- - "/docker/production/vhaudiquet.fr"
+ - "/docker/production/semeryfr"
+ - "/docker/production/vhaudiquetfr"
- "/docker/tools/excalidraw"
- "/docker/tools/hedgedoc"
- "/docker/tools/notesnook"
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index fe9f335..8c91fd1 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -11,4 +11,8 @@ repos:
entry: generate-dependabot.sh
language: script
pass_filenames: false
-
+ - id: generate-docker-swarmcd
+ name: generate docker swarmcd
+ entry: generate-docker-swarmcd.sh
+ language: script
+ pass_filenames: false
diff --git a/.swarmcd/repos.yaml b/.swarmcd/repos.yaml
new file mode 100644
index 0000000..b8175df
--- /dev/null
+++ b/.swarmcd/repos.yaml
@@ -0,0 +1,2 @@
+homeprod:
+ url: "https://github.com/vhaudiquet/homeprod"
diff --git a/.swarmcd/stacks.yaml b/.swarmcd/stacks.yaml
new file mode 100644
index 0000000..91980d6
--- /dev/null
+++ b/.swarmcd/stacks.yaml
@@ -0,0 +1,165 @@
+gitea-actions:
+ repo: homeprod
+ branch: main
+ compose_file: docker/gitea-actions/docker-compose.yml
+
+esphome:
+ repo: homeprod
+ branch: main
+ compose_file: docker/home/esphome/docker-compose.yml
+
+ha-linky:
+ repo: homeprod
+ branch: main
+ compose_file: docker/home/ha-linky/docker-compose.yml
+
+home-assistant:
+ repo: homeprod
+ branch: main
+ compose_file: docker/home/home-assistant/docker-compose.yml
+
+matter-server:
+ repo: homeprod
+ branch: main
+ compose_file: docker/home/matter-server/docker-compose.yml
+
+mosquitto-mqtt:
+ repo: homeprod
+ branch: main
+ compose_file: docker/home/mosquitto-mqtt/docker-compose.yml
+
+node-red:
+ repo: homeprod
+ branch: main
+ compose_file: docker/home/node-red/docker-compose.yml
+
+zigbee2mqtt:
+ repo: homeprod
+ branch: main
+ compose_file: docker/home/zigbee2mqtt/docker-compose.yml
+
+roundcube:
+ repo: homeprod
+ branch: main
+ compose_file: docker/infrastructure/mail/roundcube/docker-compose.yml
+
+stalwart:
+ repo: homeprod
+ branch: main
+ compose_file: docker/infrastructure/mail/stalwart/docker-compose.yml
+
+traefik:
+ repo: homeprod
+ branch: main
+ compose_file: docker/infrastructure/network/traefik/docker-compose.yml
+
+sshportal:
+ repo: homeprod
+ branch: main
+ compose_file: docker/infrastructure/sshportal/docker-compose.yml
+
+gramps:
+ repo: homeprod
+ branch: main
+ compose_file: docker/personal/gramps/docker-compose.yml
+
+jackett:
+ repo: homeprod
+ branch: main
+ compose_file: docker/personal/media/films-series/jackett/docker-compose.yml
+
+jellyfin:
+ repo: homeprod
+ branch: main
+ compose_file: docker/personal/media/films-series/jellyfin/docker-compose.yml
+
+jellyseerr:
+ repo: homeprod
+ branch: main
+ compose_file: docker/personal/media/films-series/jellyseerr/docker-compose.yml
+
+radarr:
+ repo: homeprod
+ branch: main
+ compose_file: docker/personal/media/films-series/radarr/docker-compose.yml
+
+sonarr:
+ repo: homeprod
+ branch: main
+ compose_file: docker/personal/media/films-series/sonarr/docker-compose.yml
+
+transmission:
+ repo: homeprod
+ branch: main
+ compose_file: docker/personal/media/films-series/transmission/docker-compose.yml
+
+wizarr:
+ repo: homeprod
+ branch: main
+ compose_file: docker/personal/media/films-series/wizarr/docker-compose.yml
+
+navidrome:
+ repo: homeprod
+ branch: main
+ compose_file: docker/personal/media/music/navidrome/docker-compose.yml
+
+tubearchivist:
+ repo: homeprod
+ branch: main
+ compose_file: docker/personal/media/youtube/tubearchivist/docker-compose.yml
+
+paperless:
+ repo: homeprod
+ branch: main
+ compose_file: docker/personal/paperless/docker-compose.yml
+
+radicale:
+ repo: homeprod
+ branch: main
+ compose_file: docker/personal/radicale/docker-compose.yml
+
+syncthing:
+ repo: homeprod
+ branch: main
+ compose_file: docker/personal/syncthing/docker-compose.yml
+
+tandoor:
+ repo: homeprod
+ branch: main
+ compose_file: docker/personal/tandoor/docker-compose.yml
+
+alexscript:
+ repo: homeprod
+ branch: main
+ compose_file: docker/production/alexscript/docker-compose.yml
+
+semeryfr:
+ repo: homeprod
+ branch: main
+ compose_file: docker/production/semeryfr/docker-compose.yml
+
+vhaudiquetfr:
+ repo: homeprod
+ branch: main
+ compose_file: docker/production/vhaudiquetfr/docker-compose.yml
+
+excalidraw:
+ repo: homeprod
+ branch: main
+ compose_file: docker/tools/excalidraw/docker-compose.yml
+
+hedgedoc:
+ repo: homeprod
+ branch: main
+ compose_file: docker/tools/hedgedoc/docker-compose.yml
+
+notesnook:
+ repo: homeprod
+ branch: main
+ compose_file: docker/tools/notesnook/docker-compose.yml
+
+stirling-pdf:
+ repo: homeprod
+ branch: main
+ compose_file: docker/tools/stirling-pdf/docker-compose.yml
+
diff --git a/README.md b/README.md
index f665ff7..fca5eba 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,7 @@ Running as single-node Proxmox
| 
| Repository applications | Gitea, Harbor to store code and images |
|
| Production applications | Personal applications running on the server |
-Debian and docker / docker swarm are deployed by Terraform ; then the stacks are deployed by hand for now, looking at something like [SwarmCD](https://github.com/m-adawi/swarm-cd) for the future.
+Debian and docker / docker swarm are deployed by Terraform, which also deploys [SwarmCD](https://github.com/m-adawi/swarm-cd) ; then the stacks are deployed by SwarmCD.
#### Kubernetes one-node cluster
diff --git a/docker/home/n8n/docker-compose.yaml b/docker/home/n8n/docker-compose.yaml
new file mode 100644
index 0000000..ed648c0
--- /dev/null
+++ b/docker/home/n8n/docker-compose.yaml
@@ -0,0 +1,29 @@
+services:
+ n8n:
+ image: docker.n8n.io/n8nio/n8n
+ environment:
+ - TZ=Europe/Paris
+ - N8N_SECURE_COOKIE=false
+ ports:
+ - "5678"
+ networks:
+ - default
+ - proxy
+ volumes:
+ - data:/data
+ labels:
+ - "traefik.enable=true"
+ - "traefik.http.routers.n8n.rule=Host(`n8n.lan`)"
+
+volumes:
+ data:
+ driver: local
+ driver_opts:
+ type: 'none'
+ o: 'bind'
+ device: '/app/n8n/data'
+
+networks:
+ proxy:
+ external: true
+ name: proxy
diff --git a/docker/production/semery.fr/docker-compose.yml b/docker/production/semeryfr/docker-compose.yml
similarity index 100%
rename from docker/production/semery.fr/docker-compose.yml
rename to docker/production/semeryfr/docker-compose.yml
diff --git a/docker/production/vhaudiquet.fr/docker-compose.yml b/docker/production/vhaudiquetfr/docker-compose.yml
similarity index 100%
rename from docker/production/vhaudiquet.fr/docker-compose.yml
rename to docker/production/vhaudiquetfr/docker-compose.yml
diff --git a/generate-docker-swarmcd.sh b/generate-docker-swarmcd.sh
new file mode 100755
index 0000000..20a56d1
--- /dev/null
+++ b/generate-docker-swarmcd.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+# Create .swarmcd directory if needed
+if [ ! -d .swarmcd ]; then
+ mkdir -p .swarmcd
+fi
+
+tmpfile=$(mktemp)
+
+# Make sure to cleanup our temp file on any kind of exit
+trap 'rm -f "$tmpfile"' EXIT
+
+# Find and sort all docker-compose.yml directories
+find docker -name 'docker-compose.yml' -print0 \
+ | xargs -0 -n1 dirname \
+ | sed 's|^\./||' \
+ | sort \
+ | while read -r dir; do
+ file="$dir/docker-compose.yml"
+ name=$(basename "$dir")
+ echo -e "$name:\n repo: homeprod\n branch: main\n compose_file: $file\n" >> "$tmpfile"
+ done
+
+# Overwrite file on change
+if ! [ -f .swarmcd/stacks.yaml ] || ! cmp -s "$tmpfile" .swarmcd/stacks.yaml; then
+ mv "$tmpfile" .swarmcd/stacks.yaml
+ echo "Updated .swarmcd/stacks.yaml!"
+else
+ echo "No changes to .swarmcd/stacks.yaml."
+fi
\ No newline at end of file