[Python] How do I generate browser-accessible MinIO pre-signed URLs from a FastAPI backend...

Discussão em 'Python' iniciado por Stack, Novembro 28, 2025.

  1. Stack

    Stack Membro Participativo

    Title: FastAPI + MinIO in Docker Compose: How to Generate Pre-Signed URLs Accessible Outside Docker?


    Problem Summary

    I am running a FastAPI backend and a MinIO server using Docker Compose. The backend connects to MinIO through the Docker service name (minio:9000).

    When I generate a pre-signed URL for a file using the MinIO Python SDK, the URL looks like this:

    http://minio:9000/bucket/file...

    {
    "id": 2,
    "filename": "iva_2024.pdf",
    "size_mb": 0.65,
    "size_kb": 667.02,
    "upload_date": "2025-05-09T13:51:43",
    "download_url": "http://minio:9000/b2caixa-files/Company_1/IVA_AUTOMATICO_MAIS2.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=b2caixa%2F20250509%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20250509T135222Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=aca2cae38fb705d6160519a397ab51fe36b19684e03b3d44aa65f1a3e00277a5"
    }



    This URL works inside the Docker network (e.g., when accessed from MINIO UI at /docs) but fails in external tools like my browser or Postman because minio is not resolvable outside the Docker network. Externally, I get an error like:

    getaddrinfo ENOTFOUND minio


    What I Want

    I want the backend to generate pre-signed URLs that are accessible both in the browser and in external tools. Specifically, the URLs should:

    • Use localhost:9000 or another publicly accessible domain.
    • Allow the frontend to download files through a simple endpoint (e.g., clicking an icon).

    Docker Compose Snippet

    services:
    backend:
    build: .
    environment:
    - MINIO_ENDPOINT=minio:9000
    depends_on:
    - minio

    minio:
    image: minio/minio
    ports:
    - "9000:9000"


    Code Snippet

    from minio import Minio
    from datetime import timedelta
    import os

    class MinioClient:
    def __init__(self):
    self.client = Minio(
    endpoint=os.getenv("MINIO_ENDPOINT", "minio:9000"),
    access_key=os.getenv("MINIO_ROOT_USER", "..."),
    secret_key=os.getenv("MINIO_ROOT_PASSWORD", "..."),
    secure=False
    )
    self.bucket_name = os.getenv("MINIO_BUCKET", "b2caixa-files")

    def get_file_url(self, object_name: str) -> str:
    url = self.client.presigned_get_object(
    bucket_name=self.bucket_name,
    object_name=object_name,
    expires=timedelta(seconds=3600)
    )
    # Replace Docker-internal hostname with browser-accessible one
    url = url.replace("minio:9000", "localhost:9000")
    return url


    What I Tried

    1. Setting MINIO_ENDPOINT=localhost:9000 in the backend environment, but this causes the backend to fail connecting to MinIO (because localhost inside the container refers to the container itself, not the host machine).
    2. Using the Docker service name (minio:9000), which works for backend-to-MinIO communication but results in URLs that are not accessible outside Docker.

    Continue reading...

Compartilhe esta Página