{ "nodes": [ { "id": "6b1865a7-f150-4d2b-b1f7-37c68b2173d6", "name": "Fetch Manifest Digest", "type": "n8n-nodes-base.httpRequest", "position": [ 920, -300 ], "parameters": { "url": "{{ $env.BASE_URL }}", "options": { "fullResponse": true }, "authentication": "{{ $credentials.genericCredentialType }}", "genericAuthType": "httpBasicAuth", "headerParametersUi": { "parameter": [ { "name": "Accept", "value": "application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.oci.image.index.v1+json, application/vnd.docker.distribution.manifest.list.v2+json" } ] } }, "typeVersion": 2, "notes": "This httpRequest node performs automated tasks as part of the workflow." }, { "id": "3c1daca9-3897-4596-b62d-db561f8cb047", "name": "Remove Old Tags", "type": "n8n-nodes-base.httpRequest", "onError": "continueErrorOutput", "position": [ 840, -40 ], "parameters": { "url": "{{ $env.BASE_URL }}", "options": {}, "requestMethod": "DELETE", "authentication": "{{ $credentials.genericCredentialType }}", "genericAuthType": "httpBasicAuth", "headerParametersUi": { "parameter": [ { "name": "Accept", "value": "application/vnd.docker.distribution.manifest.v2+json" } ] } }, "typeVersion": 2, "notes": "This httpRequest node performs automated tasks as part of the workflow." }, { "id": "6974749e-8c85-4334-a7e7-e964f057ed6f", "name": "Retrieve Image Tags", "type": "n8n-nodes-base.httpRequest", "position": [ 400, -300 ], "parameters": { "url": "{{ $env.BASE_URL }}", "options": {}, "authentication": "{{ $credentials.genericCredentialType }}", "genericAuthType": "httpBasicAuth", "headerParametersUi": { "parameter": [ { "name": "Accept", "value": "application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.oci.image.index.v1+json, application/vnd.docker.distribution.manifest.list.v2+json" } ] } }, "typeVersion": 2, "notes": "This httpRequest node performs automated tasks as part of the workflow." }, { "id": "30857c32-508e-4f95-8e26-c9f2fc84e074", "name": "List Images", "type": "n8n-nodes-base.httpRequest", "position": [ 40, -300 ], "parameters": { "url": "{{ $env.BASE_URL }}", "options": {}, "authentication": "{{ $credentials.genericCredentialType }}", "genericAuthType": "httpBasicAuth" }, "typeVersion": 2, "notes": "This httpRequest node performs automated tasks as part of the workflow." }, { "id": "c5965a6a-28e6-4217-a846-a849de153430", "name": "Extract Image Names", "type": "n8n-nodes-base.code", "position": [ 220, -300 ], "parameters": { "jsCode": "const images = items[0].json.repositories;\nreturn images.map(image => ({ json: { image } }));" }, "typeVersion": 2, "notes": "This code node performs automated tasks as part of the workflow." }, { "id": "b13eb6e5-1a16-4992-b0bd-9b228559fecf", "name": "Identify Tags to Remove", "type": "n8n-nodes-base.code", "position": [ 600, -40 ], "parameters": { "jsCode": "const result = [];\n\nfor (const item of items) {\n const tags = item.json.tags;\n if (tags) {\n const latestTag = tags.includes('latest') ? 'latest' : null;\n const sortedTags = tags.filter(tag => tag !== 'latest')\n .sort((a, b) => new Date(b.created) - new Date(a.created));\n const keepTags = sortedTags.slice(0, 10);\n if (latestTag) keepTags.push('latest');\n const deleteTags = sortedTags.slice(10);\n result.push(...deleteTags.map(tag => ({ json: { image: item.json.name, tag } })));\n }\n}\n\nreturn result;\n" }, "typeVersion": 2, "notes": "This code node performs automated tasks as part of the workflow." }, { "id": "da15ae49-09ee-4658-86a5-9b0a2180c637", "name": "Scheduled Trigger", "type": "n8n-nodes-base.scheduleTrigger", "position": [ -140, -300 ], "parameters": { "rule": { "interval": [ { "triggerAtHour": 1 } ] } }, "typeVersion": 1.2, "notes": "This scheduleTrigger node performs automated tasks as part of the workflow." }, { "id": "bcc347be-5520-46c0-aac9-0b14ddd8b184", "name": "Send Notification Email", "type": "n8n-nodes-base.emailSend", "position": [ 840, 180 ], "webhookId": "47f852c3-7136-4e6d-92f6-47322dbba5da", "parameters": { "text": "=Image : {{ $json.image }}\nTag : {{ $json.tag.tag }}\n\nRemoved", "options": {}, "subject": "Docker Registry Cleaner Notification", "toEmail": "to@example.com", "fromEmail": "from@example.com", "emailFormat": "text" }, "typeVersion": 2.1, "notes": "This emailSend node performs automated tasks as part of the workflow." }, { "id": "2c3770ef-cb4c-4007-8897-f4eb7ad3b7cf", "name": "Split Tags", "type": "n8n-nodes-base.splitOut", "position": [ 580, -300 ], "parameters": { "include": "selectedOtherFields", "options": { "destinationFieldName": "tag" }, "fieldToSplitOut": "tags", "fieldsToInclude": "name" }, "typeVersion": 1, "notes": "This splitOut node performs automated tasks as part of the workflow." }, { "id": "4fffa947-02cf-4608-acab-8284250cf622", "name": "Filter Valid Tags", "type": "n8n-nodes-base.filter", "position": [ 740, -300 ], "parameters": { "options": {}, "conditions": { "options": { "version": 2, "leftValue": "", "caseSensitive": true, "typeValidation": "strict" }, "combinator": "and", "conditions": [ { "id": "bb56b84e-e7cb-4867-93f8-ac40c71bde4f", "operator": { "type": "string", "operation": "notEmpty", "singleValue": true }, "leftValue": "={{ $json.tag }}", "rightValue": "" }, { "id": "acd8e00c-5fa0-4c62-ba96-9e6f456f7703", "operator": { "type": "string", "operation": "notEmpty", "singleValue": true }, "leftValue": "={{ $json.name }}", "rightValue": "" } ] } }, "typeVersion": 2.2, "notes": "This filter node performs automated tasks as part of the workflow." }, { "id": "c023ba14-d12d-497c-9b30-97db04a34c1b", "name": "Fetch Manifest Digest for Blob", "type": "n8n-nodes-base.httpRequest", "position": [ -120, -40 ], "parameters": { "url": "{{ $env.BASE_URL }}", "options": { "fullResponse": false }, "authentication": "{{ $credentials.genericCredentialType }}", "genericAuthType": "httpBasicAuth", "headerParametersUi": { "parameter": [ { "name": "Accept", "value": "application/vnd.docker.distribution.manifest.v2+json" } ] } }, "typeVersion": 2, "notes": "This httpRequest node performs automated tasks as part of the workflow." }, { "id": "f054b91e-abd4-4854-9bfa-e4a2b70f7e2c", "name": "Update Fields", "type": "n8n-nodes-base.set", "position": [ 60, -40 ], "parameters": { "options": {}, "assignments": { "assignments": [ { "id": "c970bdb8-ddbf-486b-a716-c66274a248a7", "name": "name", "type": "string", "value": "={{ $('Filter Valid Tags').item.json.name }}" }, { "id": "7ce79761-6557-413c-a9a6-5d1ca564a3df", "name": "tag", "type": "string", "value": "={{ $('Filter Valid Tags').item.json.tag }}" }, { "id": "45948a25-d35c-4e3f-9556-3d52a1a89f80", "name": "created", "type": "string", "value": "={{ $json.created }}" }, { "id": "c73a14ad-91f6-477f-b4c3-037db319b9ee", "name": "digest", "type": "string", "value": "={{ $('Fetch Manifest Digest').item.json.headers['docker-content-digest'] }}" } ] } }, "typeVersion": 3.4, "notes": "This set node performs automated tasks as part of the workflow." }, { "id": "54405505-8445-491a-8f5d-232da8c842d2", "name": "Group Tags by Image", "type": "n8n-nodes-base.code", "position": [ 420, -40 ], "parameters": { "jsCode": "const groupedData = items.reduce((acc, item) => {\n const name = item.json.name;\n if (!acc[name]) {\n acc[name] = [];\n }\n acc[name].push({\n tag: item.json.tag,\n created: item.json.created,\n digest: item.json.digest\n });\n return acc;\n}, {});\n\nreturn Object.keys(groupedData).map(name => ({\n json: { name, tags: groupedData[name] }\n}));\n" }, "typeVersion": 2, "notes": "This code node performs automated tasks as part of the workflow." }, { "id": "980aab86-44cd-47d5-b3b7-42cbae26eb09", "name": "Sort by Creation Date", "type": "n8n-nodes-base.sort", "position": [ 240, -40 ], "parameters": { "options": {}, "sortFieldsUi": { "sortField": [ { "order": "descending", "fieldName": "created" } ] } }, "typeVersion": 1, "notes": "This sort node performs automated tasks as part of the workflow." }, { "id": "0561efb9-4903-4bec-bc1a-8131e5f5de67", "name": "Send Failure Notification Email", "type": "n8n-nodes-base.emailSend", "position": [ 1120, 80 ], "webhookId": "47f852c3-7136-4e6d-92f6-47322dbba5da", "parameters": { "text": "=Image : {{ $json.image }}\nTag : {{ $json.tag.tag }}\n\nFailed", "options": {}, "subject": "[FAIL] Docker Registry Cleaner Notification", "toEmail": "to@example.com", "fromEmail": "from@example.com", "emailFormat": "text" }, "typeVersion": 2.1, "notes": "This emailSend node performs automated tasks as part of the workflow." }, { "id": "eaa28914-351c-4934-ba1c-0d39faf67ef3", "name": "Execute Garbage Collection", "type": "n8n-nodes-base.ssh", "position": [ 1120, -100 ], "parameters": { "cwd": "/opt/services/", "command": "docker compose exec -it -u root registry bin/registry garbage-collect --delete-untagged /etc/docker/registry/config.yml", "authentication": "{{ $credentials.privateKey }}" }, "typeVersion": 1, "notes": "This ssh node performs automated tasks as part of the workflow." } ], "pinData": {}, "connections": { "6b1865a7-f150-4d2b-b1f7-37c68b2173d6": { "main": [ [ { "node": "error-handler-6b1865a7-f150-4d2b-b1f7-37c68b2173d6", "type": "main", "index": 0 } ], [ { "node": "error-handler-6b1865a7-f150-4d2b-b1f7-37c68b2173d6-ae271a8d", "type": "main", "index": 0 } ], [ { "node": "error-handler-6b1865a7-f150-4d2b-b1f7-37c68b2173d6-927b6779", "type": "main", "index": 0 } ], [ { "node": "error-handler-6b1865a7-f150-4d2b-b1f7-37c68b2173d6-914d1414", "type": "main", "index": 0 } ], [ { "node": "error-handler-6b1865a7-f150-4d2b-b1f7-37c68b2173d6-3603a5a9", "type": "main", "index": 0 } ] ] }, "3c1daca9-3897-4596-b62d-db561f8cb047": { "main": [ [ { "node": "error-handler-3c1daca9-3897-4596-b62d-db561f8cb047", "type": "main", "index": 0 } ], [ { "node": "error-handler-3c1daca9-3897-4596-b62d-db561f8cb047-1cbbf61e", "type": "main", "index": 0 } ], [ { "node": "error-handler-3c1daca9-3897-4596-b62d-db561f8cb047-9630ffbc", "type": "main", "index": 0 } ], [ { "node": "error-handler-3c1daca9-3897-4596-b62d-db561f8cb047-9c9e04f1", "type": "main", "index": 0 } ], [ { "node": "error-handler-3c1daca9-3897-4596-b62d-db561f8cb047-1f2e1d14", "type": "main", "index": 0 } ] ] }, "6974749e-8c85-4334-a7e7-e964f057ed6f": { "main": [ [ { "node": "error-handler-6974749e-8c85-4334-a7e7-e964f057ed6f", "type": "main", "index": 0 } ], [ { "node": "error-handler-6974749e-8c85-4334-a7e7-e964f057ed6f-4f885bce", "type": "main", "index": 0 } ], [ { "node": "error-handler-6974749e-8c85-4334-a7e7-e964f057ed6f-42bf65f7", "type": "main", "index": 0 } ], [ { "node": "error-handler-6974749e-8c85-4334-a7e7-e964f057ed6f-8c4f98b9", "type": "main", "index": 0 } ], [ { "node": "error-handler-6974749e-8c85-4334-a7e7-e964f057ed6f-69c25a59", "type": "main", "index": 0 } ] ] }, "30857c32-508e-4f95-8e26-c9f2fc84e074": { "main": [ [ { "node": "error-handler-30857c32-508e-4f95-8e26-c9f2fc84e074", "type": "main", "index": 0 } ], [ { "node": "error-handler-30857c32-508e-4f95-8e26-c9f2fc84e074-ea99463b", "type": "main", "index": 0 } ], [ { "node": "error-handler-30857c32-508e-4f95-8e26-c9f2fc84e074-c5b24aea", "type": "main", "index": 0 } ], [ { "node": "error-handler-30857c32-508e-4f95-8e26-c9f2fc84e074-c2e94e93", "type": "main", "index": 0 } ], [ { "node": "error-handler-30857c32-508e-4f95-8e26-c9f2fc84e074-bdf1258c", "type": "main", "index": 0 } ] ] }, "c023ba14-d12d-497c-9b30-97db04a34c1b": { "main": [ [ { "node": "error-handler-c023ba14-d12d-497c-9b30-97db04a34c1b", "type": "main", "index": 0 } ], [ { "node": "error-handler-c023ba14-d12d-497c-9b30-97db04a34c1b-56c5de0f", "type": "main", "index": 0 } ], [ { "node": "error-handler-c023ba14-d12d-497c-9b30-97db04a34c1b-ca6a4dd6", "type": "main", "index": 0 } ], [ { "node": "error-handler-c023ba14-d12d-497c-9b30-97db04a34c1b-4c500945", "type": "main", "index": 0 } ], [ { "node": "error-handler-c023ba14-d12d-497c-9b30-97db04a34c1b-c76cd2ab", "type": "main", "index": 0 } ] ] }, "bcc347be-5520-46c0-aac9-0b14ddd8b184": { "main": [ [ { "node": "error-handler-bcc347be-5520-46c0-aac9-0b14ddd8b184-845df439", "type": "main", "index": 0 } ], [ { "node": "error-handler-bcc347be-5520-46c0-aac9-0b14ddd8b184-7896573f", "type": "main", "index": 0 } ], [ { "node": "error-handler-bcc347be-5520-46c0-aac9-0b14ddd8b184-a8b08510", "type": "main", "index": 0 } ], [ { "node": "error-handler-bcc347be-5520-46c0-aac9-0b14ddd8b184-2b7e53d0", "type": "main", "index": 0 } ] ] }, "0561efb9-4903-4bec-bc1a-8131e5f5de67": { "main": [ [ { "node": "error-handler-0561efb9-4903-4bec-bc1a-8131e5f5de67-eb4eb2d8", "type": "main", "index": 0 } ], [ { "node": "error-handler-0561efb9-4903-4bec-bc1a-8131e5f5de67-b1855ca4", "type": "main", "index": 0 } ], [ { "node": "error-handler-0561efb9-4903-4bec-bc1a-8131e5f5de67-86d97a0d", "type": "main", "index": 0 } ], [ { "node": "error-handler-0561efb9-4903-4bec-bc1a-8131e5f5de67-aa27f130", "type": "main", "index": 0 } ] ] } }, "name": "Httprequest Workflow", "description": "Automated workflow: Httprequest Workflow. This workflow processes data and performs automated tasks.", "settings": { "executionOrder": "v1", "saveManualExecutions": true, "callerPolicy": "workflowsFromSameOwner", "errorWorkflow": null, "timezone": "UTC", "executionTimeout": 3600, "maxExecutions": 1000, "retryOnFail": true, "retryCount": 3, "retryDelay": 1000 }, "meta": { "instanceId": "workflow-47cebf0e", "versionId": "1.0.0", "createdAt": "2025-09-29T07:07:53.090637", "updatedAt": "2025-09-29T07:07:53.090653", "owner": "n8n-user", "license": "MIT", "category": "automation", "status": "active", "priority": "high", "environment": "production" }, "tags": [ "automation", "n8n", "production-ready", "excellent", "optimized" ], "notes": "Excellent quality workflow: Httprequest Workflow. This workflow has been optimized for production use with comprehensive error handling, security, and documentation." }