AutomationFlows โ€บ Web Scraping โ€บ Trigger Coolify Deployments From New Docker Hub and Ghcr Image Digests

Trigger Coolify Deployments From New Docker Hub and Ghcr Image Digests

ByAnan @mohamed3nanโœ“ on n8n.io

๐Ÿ”„ Monitor Container Images from Docker Hub or GHCR.

Cron / scheduled triggerโ˜…โ˜…โ˜…โ˜…โ˜† complexity20 nodesHTTP Request
Web Scraping Trigger: Cron / scheduled Nodes: 20 Complexity: โ˜…โ˜…โ˜…โ˜…โ˜† Added:

This workflow corresponds to n8n.io template #16641 โ€” we link there as the canonical source.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide โ†’

Download .json
{
  "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
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing โ€” you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

๐Ÿ”„ Monitor Container Images from Docker Hub or GHCR.

Source: https://n8n.io/workflows/16641/ โ€” original creator credit. Request a take-down โ†’

More Web Scraping workflows โ†’ ยท Browse all categories โ†’

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Web Scraping

Proactively alert to service endpoint changes and pod/container issues (Pending, Not Ready, Restart spikes) using Prometheus metrics, formatted and sent to Slack.

HTTP Request
Web Scraping

Tired of being let down by the Google Drive Trigger? Rather not exhaust system resources by polling every minute? Then this workflow is for you!

HTTP Request, Execute Workflow Trigger
Web Scraping

Triggers at a regular interval or via a webhook request. Solves AWS WAF challenge then makes a request to fetch the product page. Extracts product data from the retrieved HTML page. Compares the curre

N8N Nodes Capsolver, HTTP Request
Web Scraping

Automatically monitor billable Kimai projects every weekday morning and receive a formatted HTML email when a project deadline is approaching or its hour budget is running low. If nothing requires att

Email Send, HTTP Request
Web Scraping

This workflow checks a website URL every 6 hours, detects content changes by hashing the normalized HTML, and when a change is found it uses PolyDoc to capture a full-page screenshot and emails the PN

HTTP Request, N8N Nodes Polydoc, Email Send