id: rustfs
category: service
displayName: RustFS
description: 'S3-compatible object storage (MinIO-compatible API). S3 API on `rustfs:9000`; web console on 9001 (enable with `RUSTFS_CONSOLE_ENABLE=true`), reachable from the host via `monoceros tunnel <name> rustfs:9001` and from another device via `monoceros share`.'
service:
  image: rustfs/rustfs:latest
  defaultPort: 9000
  # 9001, not the defaultPort: 9000 is the S3 API that the app and the aws CLI
  # talk to, the console on 9001 is the part a human opens. Needs
  # RUSTFS_CONSOLE_ENABLE=true, see the option below.
  httpPort: 9001
  dataMount: /data
  # rustfs runs as a fixed non-root uid (10001) and must write its
  # bind-mounted /data. The apply-created host data dir is owned by the
  # apply user; on native Linux (no Docker-Desktop ownership remapping)
  # uid 10001 can't write it and rustfs exits with a FATAL "Read-only file
  # system". Running as root lets it write the mount — the same de-facto
  # situation as postgres (whose image starts as root and chowns its data
  # dir). Verified on a native Ubuntu host.
  user: '0:0'
  healthcheck:
    # /health, not the MinIO-compatible paths: those answer 403 on this
    # image, so the service would show up as permanently unhealthy.
    test: [CMD, curl, -f, 'http://localhost:9000/health']
    interval: 10s
    timeout: 5s
    retries: 5
  client:
    # `aws s3 --endpoint-url "$RUSTFS_URL" …` with AWS_* from RUSTFS_ACCESS_KEY /
    # RUSTFS_SECRET_KEY (the briefing tells the agent the vars).
    apt: [awscli]
  connectionEnv:
    URL: http://${host}:${port}
    HOST: ${host}
    PORT: ${port}
    ACCESS_KEY: ${RUSTFS_ACCESS_KEY}
    SECRET_KEY: ${RUSTFS_SECRET_KEY}
options:
  RUSTFS_ACCESS_KEY:
    type: string
    default: rustfsadmin
    surface: env
  RUSTFS_SECRET_KEY:
    type: string
    default: rustfsadmin
    surface: env
# The service block for the project's pipeline compose file, verbatim.
deploy:
  compose: |-
    image: rustfs/rustfs:latest
    environment:
      RUSTFS_ACCESS_KEY: ${RUSTFS_ACCESS_KEY:?set it as a pipeline secret}
      RUSTFS_SECRET_KEY: ${RUSTFS_SECRET_KEY:?set it as a pipeline secret}
    volumes:
      # The objects ARE the payload here, so unlike a database in CI this keeps
      # them. No `user:` needed: the volume inherits the image's ownership.
      - rustfs-data:/data
    healthcheck:
      # /health reports iam + storage ready; the MinIO-compatible paths
      # answer 403 on this image, so they never turn healthy.
      test: [CMD, curl, -f, 'http://127.0.0.1:9000/health']
      interval: 5s
      timeout: 5s
      retries: 20
  requires: |-
    volumes:
      rustfs-data:
