A single-container web application to manage S3 and SQS resources. S3 browser supports in-place editor with syntax highlighting for known textual formats and image viewer.
- S3 Browser: Browse buckets, view file contents (JSON, XML, YAML, etc.).
- S3 Management: Edit, copy, move, and recursively delete files/folders.
- SQS Management: View queues, send/receive/purge messages.
- Single Container: Frontend and Backend served from one Docker image.
Add the following service to your docker-compose.yml:
services:
rustfs:
image: rustfs/rustfs:latest
environment:
- RUSTFS_ACCESS_KEY=test
- RUSTFS_SECRET_KEY=test
ports:
- "9000:9000"
elasticmq:
image: softwaremill/elasticmq-native:latest
ports:
- "9324:9324"
s3uitool:
image: ghcr.io/mihasic/s3uitool:latest
ports:
- "8000:8000"
environment:
- AWS_S3_ENDPOINT_URL=http://rustfs:9000
- AWS_SQS_ENDPOINT_URL=http://elasticmq:9324
- AWS_DEFAULT_REGION=us-east-1
- AWS_ACCESS_KEY_ID=test
- AWS_SECRET_ACCESS_KEY=test
depends_on:
- rustfs
- elasticmqIf you want to run the container using your local AWS CLI credentials (including SSO), copy the content of the scripts/ directory (including docker-compose.yml) to your local machine and run:
Linux / macOS:
./start.shWindows:
.\start.ps1These scripts automatically export your current AWS session credentials and pass them to the container.
The UI can switch between several AWS targets. The selected profile is part of the URL
(/<profile>/s3/<bucket>), so links and bookmarks stay tied to one account. Profiles are
fully isolated: separate SDK clients, separate caches, and no cross-profile copy.
Profiles come from three sources:
-
The global
AWS_*variables — always present, always the default profile. This is the behaviour every existing deployment already has; nothing changes if you set nothing else. Rename it withDEFAULT_PROFILE_ID/DEFAULT_PROFILE_LABEL. -
Extra bindings declared as
PROFILE_<id>_*groups, for example a second bucket store or another emulator:environment: - PROFILE_staging_LABEL=Staging - PROFILE_staging_REGION=eu-west-1 - PROFILE_staging_ACCESS_KEY_ID=AKIA... - PROFILE_staging_SECRET_ACCESS_KEY=... # or delegate credentials to a ~/.aws profile instead of static keys: - PROFILE_prod_AWS_PROFILE=prod-sso
Supported suffixes:
LABEL,REGION,ENDPOINT_URL,S3_ENDPOINT_URL,SQS_ENDPOINT_URL,ACCESS_KEY_ID,SECRET_ACCESS_KEY,SESSION_TOKEN,AWS_PROFILE,ENABLE_S3,ENABLE_SQS. Anything omitted falls back to the global value. -
Profiles found in
~/.aws/configand~/.aws/credentials, including SSO,credential_processand assume-role profiles. This needs the files to be readable by the server, so it does nothing in the stock container unless you mount them:volumes: - ~/.aws:/root/.aws:ro
Security: this app has no authentication. Anyone who can reach it can use every profile it lists. Do not mount
~/.aws(or setENABLE_PROFILE_DISCOVERY=0) on a host reachable beyond localhost, and preferAWS_CONFIG_PROFILESto expose only the profiles you mean to.
Profile ids are slugified for the URL, and ids that would collide with an API route or a
static asset (api, s3, sqs, assets, …) are renamed with a warning at startup.
Pre-profile URLs such as /s3/documents?prefix=project/ redirect to the default profile,
and the unprefixed /api/s3/... endpoints keep working.
| Environment Variable | Default | Description |
|---|---|---|
AWS_S3_ENDPOINT_URL |
http://localhost:9000 |
URL of the S3 endpoint (e.g., RustFS). |
AWS_SQS_ENDPOINT_URL |
http://localhost:9324 |
URL of the SQS endpoint (e.g., ElasticMQ). |
AWS_ENDPOINT_URL |
None |
Shared endpoint. Used for both services only when service-specific endpoints are not set. |
AWS_DEFAULT_REGION |
us-east-1 |
AWS Region. |
AWS_ACCESS_KEY_ID |
test |
AWS Access Key ID. |
AWS_SECRET_ACCESS_KEY |
test |
AWS Secret Access Key. |
ENABLE_S3 |
true |
Enable S3 features. Overridable per profile. |
ENABLE_SQS |
true |
Enable SQS features. Overridable per profile. |
DEFAULT_PROFILE_ID |
default |
URL id of the profile built from the global AWS_* variables. |
DEFAULT_PROFILE_LABEL |
Default |
Display name of that profile in the switcher. |
PROFILE_<id>_* |
None |
Declares an extra profile. See Multiple AWS Profiles. |
ENABLE_PROFILE_DISCOVERY |
true |
Read ~/.aws for additional profiles. Set to 0 to expose only the ones you configured. |
AWS_CONFIG_PROFILES |
None |
Comma-separated allowlist limiting which ~/.aws profiles are exposed. |
MAX_UPLOAD_MB |
512 |
Maximum multipart upload size. Bun buffers the body in memory, so this also bounds per-upload memory. |
PORT |
8000 |
Port the server listens on. |
STATIC_DIR |
/app/static |
Directory holding the built frontend. |
Endpoint precedence:
AWS_S3_ENDPOINT_URLfor S3 andAWS_SQS_ENDPOINT_URLfor SQSAWS_ENDPOINT_URLas a shared fallback for both services
- Docker
- Docker Compose
- Bun (for local frontend and backend dev)
Create a .env file in the project root to configure local S3/SQS endpoints for development
(the dev:api and seed scripts load it):
AWS_S3_ENDPOINT_URL=http://localhost:9000
AWS_SQS_ENDPOINT_URL=http://localhost:9324
AWS_DEFAULT_REGION=us-east-1
AWS_ACCESS_KEY_ID=test
AWS_SECRET_ACCESS_KEY=testapi/: TypeScript Hono backend (runs on Bun)app/: React/Vite frontende2e/: Playwright End-to-End tests
bun install
bun run dev:api # http://localhost:8000, hot reloadbun install
bun run dev:app # http://localhost:5173, proxies /api to :8000bun run dev
bun run dev:local # same, but pointed at the local RustFS/ElasticMQ emulatorsNeeds the emulators running (docker compose up -d rustfs elasticmq):
bun run test:apiThe default config starts the whole dev stack itself (bun run dev) and reuses one that
is already up:
cd e2e && bunx playwright testAlternatively, point Playwright straight at the built container and skip Vite:
docker compose up -d --build
bun run seed
cd e2e && APP_PORT=8000 bunx playwright testTo release a new version:
- Go to the "Actions" tab in GitHub.
- Select the "Release" workflow.
- Click "Run workflow".
- Enter the version tag (e.g.,
0.1.0). - The workflow will build the Docker image and push it to GHCR.
MIT


0 comments
log in to comment.