The AWS console is great until you want to give someone a read-only link to a single bucket. Then it’s terrible: you have to mint an IAM user or a federated role, walk them through the console, scope it down, deal with their MFA, and so on. All they wanted was to browse a folder.

s3xplorer started as a weekend POC to play with the AWS Go SDK v2 and the minio client, and turned into the tool I now use to expose a bucket to humans without giving them AWS credentials.

What it does

You give it a YAML config with S3 credentials and a bucket name. It exposes a small web UI where users can navigate the bucket as if it were a file tree, with a light/dark mode, optional prefix scoping, and (optionally) a “restore from Glacier” button for archived objects.

It’s deliberately limited: read-mostly, one bucket per instance, no upload, no delete from the UI. The point is to be the boring “give people a link” layer in front of S3.

v0.5.0: PostgreSQL changed everything

The version that made this tool actually useful is 0.5.0. Before that, every browse hit S3 directly — which is fine for a small bucket, painful for one with 100k+ objects, and expensive at scale (every ListObjectsV2 is a billable call).

The new architecture introduces a PostgreSQL backend:

  • A background scanner periodically syncs the bucket into Postgres on a cron schedule.
  • The web UI reads from the database, not from S3. Browsing is instant, even on huge buckets.
  • Deletion sync is optional, so the database can be kept in lockstep with the bucket.
  • The first scan can take a while; subsequent access is essentially free.

That trade-off — slightly stale data, instant UI — fits exactly the use case I built it for.

Configuring it

A config for a local MinIO instance, with the database backend on:

s3:
  endpoint: http://127.0.0.1:9090
  region: "us-east-1"
  access_key: minioadminn
  api_key: minioadminn
  bucket: example
  prefix: rando/
  restore_days: 1
  enable_glacier_restore: false
  skip_bucket_validation: false

database:
  url: "postgres://postgres:postgres@localhost:5432/s3xplorer?sslmode=disable"

scan:
  enable_background_scan: true
  cron_schedule: "0 2 * * *"   # daily at 2 AM
  enable_initial_scan: false
  enable_deletion_sync: true

bucket_sync:
  enable: true
  sync_threshold: "24h"
  delete_threshold: "168h"
  max_retries: 3

log_level: info

Two things worth pointing out:

  • The prefix setting scopes the UI to a sub-path. Combined with bucket policies, that’s how I share “just this folder” with someone.
  • enable_glacier_restore is off by default. If your bucket has Glacier objects and you want users to be able to trigger restores from the UI, flip it on.

Running it

Three ways, in order of friction:

# Binary
s3xplorer -f config.yaml

# Docker
docker run -v $(pwd)/config.yaml:/cfg.yaml -p 8081:8081 sgaunet/s3xplorer:latest

# Helm chart, for Kubernetes
helm repo add s3xplorer https://sgaunet.github.io/helm-s3xplorer/
helm repo update
helm search repo s3xplorer

For a local demo with MinIO, the README ships a docker-compose.yml that brings up MinIO and s3xplorer together. That’s the path I recommend if you just want to kick the tyres.

A few honest words about scope

The author of this tool is me, and I’ll be the first to say it’s not a competitor to mature S3 explorers. From the README: it started as a POC and “still needs refactor and improvements.” That’s still true. What it does have going for it:

  • Dead simple deploy story (one binary, one config, optional Postgres)
  • A genuinely useful niche: read-only, one-bucket-at-a-time UI for non-AWS humans
  • The Glacier restore button, which I find myself reaching for surprisingly often
  • A Helm chart that just works on a small cluster
  • An IAM CloudFormation stack in docs/ so you can spin up the right scoped policy in one click

Where to find it

If you’ve ever been asked “can you just send me the files in that bucket?” and groaned at the IAM dance ahead of you, give s3xplorer a try. Stand it up once, hand out the URL, move on with your day.