From bdfc028ca1604ebeac9337a516cf07e61cb2885a Mon Sep 17 00:00:00 2001 From: Sergei Poljanski Date: Wed, 11 Nov 2026 03:44:37 +0400 Subject: [PATCH] Route s3.asxp.io to Garage The data is copied and verified and both apps sign with their Garage keys, so send s3.asxp.io to Garage's S3 API. MinIO loses its route and stays up, unrouted, as the way back. Garage answers no anonymous S3 request. Unsigned GET and HEAD of /public/ go to its web endpoint instead, with the Host header the endpoint picks the bucket by, so the links handed out so far keep working. Signed requests for that bucket still reach the S3 API. Assisted-by: Claude:fable-5-2 --- docker-compose.yml | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index ae53edb..05cc453 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,6 +36,8 @@ services: - storage restart: "no" + # Kept only as the way back until Garage has proven itself: not routed, + # not bootstrapped, its data frozen as of the switch. minio: image: minio/minio:latest container_name: storage-minio @@ -49,25 +51,14 @@ services: - minio_data:/data networks: - storage - - traefik healthcheck: test: ["CMD", "mc", "ready", "local"] interval: 5s timeout: 5s retries: 10 labels: - - "traefik.enable=true" - - "traefik.docker.network=traefik" - - "traefik.http.routers.minio-s3.rule=Host(`s3.asxp.io`)" - - "traefik.http.routers.minio-s3.entrypoints=websecure" - - "traefik.http.routers.minio-s3.tls=true" - - "traefik.http.routers.minio-s3.tls.certresolver=letsencrypt" - - "traefik.http.routers.minio-s3.service=minio-s3" - - "traefik.http.services.minio-s3.loadbalancer.server.port=9000" + - "traefik.enable=false" - # Replaces MinIO (abandoned upstream; its images are gone from the - # registries). Not routed yet: MinIO still answers s3.asxp.io until the data - # is copied and the apps are switched. garage: image: dxflrs/garage:v2.5.0 container_name: storage-garage @@ -87,7 +78,28 @@ services: timeout: 5s retries: 10 labels: - - "traefik.enable=false" + - "traefik.enable=true" + - "traefik.docker.network=traefik" + # The S3 API. + - "traefik.http.routers.garage-s3.rule=Host(`s3.asxp.io`)" + - "traefik.http.routers.garage-s3.entrypoints=websecure" + - "traefik.http.routers.garage-s3.tls=true" + - "traefik.http.routers.garage-s3.tls.certresolver=letsencrypt" + - "traefik.http.routers.garage-s3.service=garage-s3" + - "traefik.http.services.garage-s3.loadbalancer.server.port=3900" + # Anonymous reads of the public bucket: unsigned GET/HEAD of + # /public/ goes to the web endpoint as Host public.web.garage, + # path /. Signed requests still reach the S3 API above. + - "traefik.http.routers.garage-public.rule=Host(`s3.asxp.io`) && PathPrefix(`/public/`) && (Method(`GET`) || Method(`HEAD`)) && !HeaderRegexp(`Authorization`, `.+`) && !QueryRegexp(`X-Amz-Signature`, `.+`)" + - "traefik.http.routers.garage-public.priority=1000" + - "traefik.http.routers.garage-public.entrypoints=websecure" + - "traefik.http.routers.garage-public.tls=true" + - "traefik.http.routers.garage-public.tls.certresolver=letsencrypt" + - "traefik.http.routers.garage-public.service=garage-web" + - "traefik.http.routers.garage-public.middlewares=garage-public-strip,garage-public-host" + - "traefik.http.middlewares.garage-public-strip.stripprefix.prefixes=/public" + - "traefik.http.middlewares.garage-public-host.headers.customrequestheaders.Host=public.web.garage" + - "traefik.http.services.garage-web.loadbalancer.server.port=3902" volumes: pg_data: