The goal

I want a service that automatically converts images to WebP, and serves the converted image when a mobile client requests the original image.

Requirements

  1. When an image is uploaded to S3, send an event to a server to convert the image to WebP
  2. After converting it into WebP, save it into the bucket
    (The WebP Server is good, but I want to serve the WebP content statically)
  3. For each mobile image request, redirect the request to the WebP image

After resolving the reverse proxy URL rewrite PoC , let’s focus on the S3 event triggering PoC.

Triggering Event for object upload

AWS S3 has BucketNotification support,
but it is missing in Garage .
So I had to add another service to notify the server when an image is uploaded.

Then I noticed something in the docker logs: it seems to show the request.

2025-11-16T17:48:07.958297Z INFO garage_api_common::generic_server: [::ffff:172.18.0.4]:45474 (key GKxxxxxxxxxxxxxxxxx) PUT /test-s3/test-image.jpeg

Meet LoggiFly

LoggiFly is a Docker log utility that can catch keywords in the logs,
alert the user through various notification services (e.g. ntfy), and even send webhooks, which is exactly the interesting part here.

Of course you can use a full log collector stack, but I don’t want to set one up just for this purpose.

Setup

It is easy to spin it up using Docker Compose (I used 11notes/socket-proxy).
For the config.yaml that triggers the alert, you can check the docs right here .
If you want to match by regex, make sure you are using Python regex syntax.

config.yaml

containers:
  garage: <- the container name you want to monitor
    keywords:
      - regex: ^.*\(key\s+(?P<s3key>\w+)\)\s+(PUT)\s+(?P<s3url>\S+)$
        webhook_url: "http://127.0.0.1/" <- I sent it to my local honeypot for testing
        hide_regex_in_title: true

This regex is not perfect, because a PUT request is not necessarily a PUT object request, but you can always handle that part server-side later.

Logs in LoggiFly

loggifly        | 2025-11-21 10:23:59,405 - INFO - The following keywords were found in garage: ['Regex-Pattern'].
loggifly        |   -----  LOG-ENTRY  -----
loggifly        |  | 2025-11-21T10:23:58.402154Z  INFO garage_api_common::generic_server: 127.0.0.1 (via [::ffff:172.18.0.2]:49744) (key GKxxxxxxxxxxxxxxxxx) PUT /test-s3/test-image.jpeg
loggifly        |    -----------------------
loggifly        | 2025-11-21 10:24:00,220 - INFO - Webhook sent successfully.

And I could see the JSON payload in my honeypot, confirming that it was triggered.

{\"monitor_type\": \"container\", \"unit_name\": \"garage\", \"keywords\": [\"Regex-Pattern\"], \"title\": \"'Regex-Pattern' found in garage\", \"message\": \"2025-11-21T10:23:58.402154Z  INFO garage_api_common::generic_server: 127.0.0.1 (via [::ffff:172.18.0.2]:49744) (key GKxxxxxxxxxxxxxxxxx) PUT /test-s3/test-image.jpeg) PUT /test-s3/test-image.jpeg", \"host\": \"\"}

That’s another puzzle solved, leaving only the final converter server implementation.