{
  "id": "UK5DJHAZpymp0jwF",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "\ud83d\udd04 Monitor Container Images from Docker Hub and GHCR to Trigger Coolify Deployments",
  "tags": [],
  "nodes": [
    {
      "id": "758ecbe4-87ca-4a98-88ae-4d33007bacba",
      "name": "Post Processing Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4816,
        304
      ],
      "parameters": {
        "width": 896,
        "height": 960,
        "content": "## \ud83d\udd04 Monitor Container Images from Docker Hub and GHCR to Trigger Coolify Deployments\n\nThis workflow monitors container image registries for new digests and triggers a deployment whenever an update is detected. It supports Docker Hub and GitHub Container Registry (GHCR), making it easy to keep self-hosted apps up to date.\n\n## Who\u2019s it for\nDevOps engineers, homelab enthusiasts, and developers who manage self-hosted applications using container images and want to automate update detection without manually checking registries.\n\n## How it works\n- Runs on a schedule to check for new image versions.\n- Defines repository tags and deployment IDs for Docker Hub and GHCR images.\n- Fetches the latest image digest from each registry (handling GHCR auth tokens).\n- Removes digests already seen in previous runs.\n- Builds a standardized metadata object for each new update.\n- Merges both branches and triggers a deployment API call (e.g., restarting a Coolify service).\n\n## Requirements\n- Registry image references for the images you want to monitor.\n- Authentication credentials for your deployment platform API.\n\n## How to set up\n1. Configure the Schedule Trigger to set how often checks run.\n2. Open the \"Set Variables\" nodes, add your `repository_tag` arrays, and match them with your deployment IDs. Ensure the order corresponds by index (e.g., the first image maps to the first UUID, the second image to the second UUID, and so on).\n3. Open the final HTTP Request node and replace the URL and authentication with your own deployment platform (Coolify, Portainer, Kubernetes, etc.).\n\n## How to customize\n- Add more images by extending the repository lists in the Variables nodes.\n- Replace the final deployment step with Portainer, Docker Swarm, or a custom webhook.\n- Add notifications (e.g., Slack, Discord) or approval steps before deployment."
      },
      "typeVersion": 1
    },
    {
      "id": "db649a79-8521-45fa-b561-9b4f1433e0b7",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        5552,
        656
      ],
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "f552b79f-627d-471c-b5f5-629485a67d41",
      "name": "Triggers Section Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        6896,
        848
      ],
      "parameters": {
        "color": 4,
        "width": 656,
        "height": 416,
        "content": "## Mohamed Anan\n\n![Anan](https://1.gravatar.com/avatar/2c212891367a29a481ce306de2a3c936abab9dd120e11aae24782b47f5d856bd?size=64)\n\n**Engineer** | `Problem Solver` | **n8n Power User**\n\n---\n\n- [x] Recipient of the **[2025 n8n Community Award: Forum Support](https://community.n8n.io/badges/114/2025-community-awards?username=mohamed3nan)**.\n- [x] [Top Supporter](https://community.n8n.io/badges/112/top-supporter?username=mohamed3nan) in the n8n community with **500+ hours** of contribution and **300+ solutions** provided, ranked **[#10 on the all-time leaderboard](https://community.n8n.io/leaderboard/1)**.\n---\n\ud83d\udcac [Community Profile](https://community.n8n.io/u/mohamed3nan/summary) | \u26a1 [n8n Workflows](https://n8n.io/creators/mohamed3nan/) | \ud83d\udcbc [LinkedIn](https://www.linkedin.com/in/mohamed3nan)"
      },
      "typeVersion": 1
    },
    {
      "id": "8ac527fe-f794-48c0-81f7-ace2fb0031b3",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5728,
        304
      ],
      "parameters": {
        "color": 7,
        "width": 1152,
        "height": 960,
        "content": "## Docker Hub image lookup\nDefine the Docker Hub images to monitor using the repository_tag array (for example [\"n8nio/n8n:beta\", \"chatwoot/chatwoot:latest\"]) and map each image to its corresponding deployment ID using coolify_UUID.\n\nEach repository tag is processed individually to fetch its latest image digest from Docker Hub. Previously seen digests are filtered out, and any new digest is transformed into a standardized metadata object before being passed to the deployment step."
      },
      "typeVersion": 1
    },
    {
      "id": "c825a7c6-45bb-417c-8123-cb3370a94bda",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5728,
        928
      ],
      "parameters": {
        "color": 7,
        "width": 1152,
        "height": 336,
        "content": "## GHCR digest lookup\n\nDefine the GHCR images to monitor using the repository_tag array (for example [\"tashfeenahmed/freellmapi:latest\"]) and map each image to its corresponding deployment ID using coolify_UUID.\n\nEach repository tag is processed individually. The workflow first retrieves a temporary authentication token, then fetches the latest OCI image digest from GHCR. Previously seen digests are filtered out, and any new digest is transformed into the same standardized metadata object before being passed to the deployment step."
      },
      "typeVersion": 1
    },
    {
      "id": "3e8c1e36-b7e1-40fa-8d0e-b42703086bde",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        6896,
        304
      ],
      "parameters": {
        "color": 7,
        "width": 320,
        "height": 528,
        "content": "## Merge image metadata\nCombines the Docker Hub and GHCR branches into a single stream so the next step can handle them the same way."
      },
      "typeVersion": 1
    },
    {
      "id": "01121134-c0b9-4430-9061-b8f864b7a1ff",
      "name": "Restart Coolify Service",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        7312,
        656
      ],
      "parameters": {
        "url": "=https://your-coolify-instance.com/api/v1/services/{{ $json.coolify_UUID }}/restart?latest=true",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "a5dd4037-3542-43fe-9c89-a17e03322c6d",
      "name": "Merge All Image Metadata",
      "type": "n8n-nodes-base.merge",
      "position": [
        6992,
        656
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "696e9ef6-32d7-4a96-9839-e636f535836b",
      "name": "Deduplicate Docker Hub Digests",
      "type": "n8n-nodes-base.removeDuplicates",
      "position": [
        6528,
        560
      ],
      "parameters": {
        "options": {},
        "operation": "removeItemsSeenInPreviousExecutions",
        "dedupeValue": "={{ $json.digest }}"
      },
      "typeVersion": 2
    },
    {
      "id": "30ca1f22-be84-4a35-a67e-fe19d85594c8",
      "name": "Deduplicate GHCR Digests",
      "type": "n8n-nodes-base.removeDuplicates",
      "position": [
        6528,
        752
      ],
      "parameters": {
        "options": {},
        "operation": "removeItemsSeenInPreviousExecutions",
        "dedupeValue": "={{ $json.headers[\"docker-content-digest\"] }}"
      },
      "typeVersion": 2
    },
    {
      "id": "80e599d9-bec5-4c03-a52f-d0b62f94be7a",
      "name": "Fetch Docker Hub Tag Digest",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        6240,
        560
      ],
      "parameters": {
        "url": "=https://registry.hub.docker.com/v2/repositories/{{ $json.repository_tag.split(':')[0] }}/tags/{{ $json.repository_tag.split(':')[1] }}",
        "options": {
          "response": {
            "response": {}
          }
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "588ce291-6ce9-48ed-a51f-b31ef4366045",
      "name": "Fetch GHCR OCI Index Digest",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        6336,
        752
      ],
      "parameters": {
        "url": "=https://ghcr.io/v2/{{ $('Split GHCR Repo Tags').item.json.repository_tag.split(':')[0] }}/manifests/{{ $('Split GHCR Repo Tags').item.json.repository_tag.split(':')[1] }}",
        "method": "HEAD",
        "options": {
          "response": {
            "response": {
              "fullResponse": true,
              "responseFormat": "json"
            }
          }
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{$json.token}}"
            },
            {
              "name": "Accept",
              "value": "application/vnd.oci.image.index.v1+json, application/vnd.oci.image.manifest.v1+json, application/vnd.docker.distribution.manifest.list.v2+json, application/vnd.docker.distribution.manifest.v2+json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "de2fee58-89e6-4a76-a9aa-d3d6ed7b604d",
      "name": "Split Docker Hub Repo Tags",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        5952,
        560
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "repository_tag, coolify_UUID"
      },
      "typeVersion": 1
    },
    {
      "id": "6b44bb3c-8281-4347-8aa5-b22915325e88",
      "name": "Fetch GHCR Auth Token",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        6144,
        752
      ],
      "parameters": {
        "url": "=https://ghcr.io/token?service=ghcr.io&scope=repository:{{ $json.repository_tag.split(':')[0] }}:pull",
        "options": {
          "response": {
            "response": {}
          }
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "586a5b5c-70ea-4749-836d-58399f8d1369",
      "name": "Split GHCR Repo Tags",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        5952,
        752
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "repository_tag, coolify_UUID"
      },
      "typeVersion": 1
    },
    {
      "id": "87a9ded7-9d0c-4d71-a123-e093bd8a73fa",
      "name": "Set GHCR Variables",
      "type": "n8n-nodes-base.set",
      "position": [
        5776,
        752
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "repo-assign",
              "name": "repository_tag",
              "type": "array",
              "value": "[\"tashfeenahmed/freellmapi:latest\"]"
            },
            {
              "id": "36a64f55-1840-4cb7-8b61-4c0a8a7a7dc9",
              "name": "coolify_UUID",
              "type": "array",
              "value": "[\"your-freellmapi-service-uuid\"]"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "dd363dd1-091e-444c-930f-f0420dfb6f17",
      "name": "Set Docker Hub Variables",
      "type": "n8n-nodes-base.set",
      "position": [
        5776,
        560
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "repo-assign",
              "name": "repository_tag",
              "type": "array",
              "value": "[\"n8nio/n8n:beta\", \"chatwoot/chatwoot:latest\"]"
            },
            {
              "id": "d2738fc8-8879-4db7-b91b-f1ce0d9633a1",
              "name": "coolify_UUID",
              "type": "array",
              "value": "[\"your-n8n-service-uuid\", \"your-chatwoot-service-uuid\"]"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "83237ba9-38fc-4b70-b214-5356cfa422d0",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        7232,
        304
      ],
      "parameters": {
        "color": 7,
        "width": 320,
        "height": 528,
        "content": "## Trigger deployment\nUses the merged metadata to call the deployment endpoint and restart the matching service.\n\nCoolify is used here as the example, but this step can be replaced with any API, webhook, or further operation."
      },
      "typeVersion": 1
    },
    {
      "id": "6015db66-afb3-4f8a-9cfd-ee7183770a84",
      "name": "Docker Hub Image Metadata",
      "type": "n8n-nodes-base.set",
      "position": [
        6720,
        560
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "72b52f47-50e1-4417-b6da-a2bf531903bb",
              "name": "registry",
              "type": "string",
              "value": "dockerhub"
            },
            {
              "id": "252fcc33-f565-4e4e-a98c-0fbcc60a43ac",
              "name": "image",
              "type": "string",
              "value": "=docker.io/{{ $('Split Docker Hub Repo Tags').item.json.repository_tag }}"
            },
            {
              "id": "693d9914-009c-4dd1-be81-81205acfe13d",
              "name": "checked_at",
              "type": "string",
              "value": "={{ $now }}"
            },
            {
              "id": "e2fc4ace-e639-4cc9-9721-339a904cea8f",
              "name": "digest",
              "type": "string",
              "value": "={{ $json.digest }}"
            },
            {
              "id": "b540080c-4d51-4d8b-b2a1-a6d867c98dbd",
              "name": "coolify_UUID",
              "type": "string",
              "value": "={{ $('Split Docker Hub Repo Tags').item.json.coolify_UUID }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "877639a2-3fb2-4fee-93ab-318c89bd0c1c",
      "name": "GHCR Image Metadata",
      "type": "n8n-nodes-base.set",
      "position": [
        6720,
        752
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "ddaa840c-db6f-4695-bf45-b09a11e9b39c",
              "name": "registry ",
              "type": "string",
              "value": "ghcr"
            },
            {
              "id": "252fcc33-f565-4e4e-a98c-0fbcc60a43ac",
              "name": "image",
              "type": "string",
              "value": "=https://ghcr.io/{{ $('Split GHCR Repo Tags').item.json.repository_tag }}"
            },
            {
              "id": "693d9914-009c-4dd1-be81-81205acfe13d",
              "name": "checked_at",
              "type": "string",
              "value": "={{ $now }}"
            },
            {
              "id": "f46478ba-adfb-4812-a30a-0ee3a2bd198a",
              "name": "digest",
              "type": "string",
              "value": "={{ $json.headers[\"docker-content-digest\"] }}"
            },
            {
              "id": "5bd8ad50-0045-4c98-8e01-835fb01013ca",
              "name": "coolify_UUID",
              "type": "string",
              "value": "={{ $('Split GHCR Repo Tags').item.json.coolify_UUID }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "e6bbdf37-8baa-4d0a-9b32-9a5f38bebce4",
  "nodeGroups": [],
  "connections": {
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Set Docker Hub Variables",
            "type": "main",
            "index": 0
          },
          {
            "node": "Set GHCR Variables",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set GHCR Variables": {
      "main": [
        [
          {
            "node": "Split GHCR Repo Tags",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GHCR Image Metadata": {
      "main": [
        [
          {
            "node": "Merge All Image Metadata",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Split GHCR Repo Tags": {
      "main": [
        [
          {
            "node": "Fetch GHCR Auth Token",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch GHCR Auth Token": {
      "main": [
        [
          {
            "node": "Fetch GHCR OCI Index Digest",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Deduplicate GHCR Digests": {
      "main": [
        [
          {
            "node": "GHCR Image Metadata",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge All Image Metadata": {
      "main": [
        [
          {
            "node": "Restart Coolify Service",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Docker Hub Variables": {
      "main": [
        [
          {
            "node": "Split Docker Hub Repo Tags",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Docker Hub Image Metadata": {
      "main": [
        [
          {
            "node": "Merge All Image Metadata",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Docker Hub Repo Tags": {
      "main": [
        [
          {
            "node": "Fetch Docker Hub Tag Digest",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Docker Hub Tag Digest": {
      "main": [
        [
          {
            "node": "Deduplicate Docker Hub Digests",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch GHCR OCI Index Digest": {
      "main": [
        [
          {
            "node": "Deduplicate GHCR Digests",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Deduplicate Docker Hub Digests": {
      "main": [
        [
          {
            "node": "Docker Hub Image Metadata",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}