Coolify allows you to host a Distribution docker registry backed by S3 or GCS

To use with GCS we can add a GCS service_key.json file and use Coolify’s mounted file editor to paste in the contents of a key exported from Google GCP.

services:
  registry:
    image: 'registry:2'
    environment:
      - SERVICE_FQDN_REGISTRY_5000
      - REGISTRY_AUTH=htpasswd
      - REGISTRY_AUTH_HTPASSWD_REALM=Registry
      - REGISTRY_AUTH_HTPASSWD_PATH=/auth/registry.password
    volumes:
      -
        type: bind
        isDirectory: false
        source: ./auth/service_key.json
        target: /auth/service_key.json
      -
        type: bind
        source: ./auth/registry.password
        target: /auth/registry.password
        isDirectory: false
      -
        type: bind
        source: ./config/config.yml
        target: /etc/docker/registry/config.yml
        isDirectory: false
      -
        type: bind
        source: ./data
        target: /data
        isDirectory: true

We can then configure the storage driver as described in the Google Cloud Storage Config or S3 Storage Config guides.

Traefik

We need to add some extra commands and labels to avoid problems with images not uploading/timing out/being too big.

Specifically:

commands:

	command:
	  # other commands here
      - '--serversTransport.forwardingTimeouts.dialTimeout=60s'
      - '--serversTransport.forwardingTimeouts.responseHeaderTimeout=600s'
      - '--serversTransport.forwardingTimeouts.idleConnTimeout=600s'
      - '--entrypoints.http.transport.respondingTimeouts.readTimeout=600s'
      - '--entrypoints.http.transport.respondingTimeouts.writeTimeout=600s'
      - '--entrypoints.https.transport.respondingTimeouts.readTimeout=600s'
      - '--entrypoints.https.transport.respondingTimeouts.writeTimeout=600s'

and labels:

 
    labels:
       # other labels here
      - traefik.http.middlewares.size-limit.sizeLimits.maxBodySize=500000000
 

Full example:

version: '3.8'
networks:
  coolify:
    external: true
services:
  traefik:
    container_name: coolify-proxy
    image: 'traefik:v2.11'
    restart: unless-stopped
    extra_hosts:
      - 'host.docker.internal:host-gateway'
    networks:
      - coolify
    ports:
      - '80:80'
      - '443:443'
      - '8080:8080'
    healthcheck:
      test: 'wget -qO- http://localhost:80/ping || exit 1'
      interval: 4s
      timeout: 2s
      retries: 5
    volumes:
      - '/var/run/docker.sock:/var/run/docker.sock:ro'
      - '/data/coolify/proxy:/traefik'
    command:
      - '--ping=true'
      - '--ping.entrypoint=http'
      - '--api.dashboard=true'
      - '--api.insecure=false'
      - '--entrypoints.http.address=:80'
      - '--entrypoints.https.address=:443'
      - '--entrypoints.http.http.encodequerysemicolons=true'
      - '--entryPoints.http.http2.maxConcurrentStreams=50'
      - '--entrypoints.https.http.encodequerysemicolons=true'
      - '--entryPoints.https.http2.maxConcurrentStreams=50'
      - '--providers.docker.exposedbydefault=false'
      - '--providers.file.directory=/traefik/dynamic/'
      - '--providers.file.watch=true'
      - '--certificatesresolvers.letsencrypt.acme.httpchallenge=true'
      - '--certificatesresolvers.letsencrypt.acme.storage=/traefik/acme.json'
      - '--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http'
      - '--providers.docker=true'
      - '--serversTransport.forwardingTimeouts.dialTimeout=60s'
      - '--serversTransport.forwardingTimeouts.responseHeaderTimeout=600s'
      - '--serversTransport.forwardingTimeouts.idleConnTimeout=600s'
      - '--entrypoints.http.transport.respondingTimeouts.readTimeout=600s'
      - '--entrypoints.http.transport.respondingTimeouts.writeTimeout=600s'
      - '--entrypoints.https.transport.respondingTimeouts.readTimeout=600s'
      - '--entrypoints.https.transport.respondingTimeouts.writeTimeout=600s'
    labels:
      - traefik.enable=true
      - traefik.http.routers.traefik.entrypoints=http
      - traefik.http.routers.traefik.service=api@internal
      - traefik.http.services.traefik.loadbalancer.server.port=8080
      - coolify.managed=true
      - traefik.http.middlewares.size-limit.sizeLimits.maxBodySize=500000000