Open Source · MIT License

Your storage.
Your rules.

S3-compatible object storage on your own VPS — with automated backups, a web panel, a CLI, and a full REST API. Powered by Garage, secured by Caddy.

Get Started View on GitHub
# Clone and install
$ sudo git clone https://github.com/andreapollastri/johnny /opt/johnny
$ cd /opt/johnny
$ sudo bash scripts/autoinstall.sh

# You're ready
$ source /etc/johnny/credentials/default-s3.env
$ aws s3 ls --endpoint-url "$AWS_ENDPOINT_URL"

Everything you need, nothing you don't

Production-ready object storage with batteries included. No vendor lock-in, no hidden costs.

S3-Compatible Storage

Powered by Garage — a lightweight, self-contained storage engine. Works with any AWS SDK, the aws CLI, or S3-compatible client.

One-Command Install

An interactive script provisions Garage, obtains TLS certificates via Caddy, configures rclone for backups, and wires up nightly cron — all in one run.

Automated Backups

Nightly SFTP sync of every bucket to one or more remote servers with date-based retention. Optional S3-to-S3 replication for cross-node redundancy.

Web Panel with 2FA

Optional Laravel dashboard to browse buckets, manage objects, create and revoke API keys — secured with TOTP two-factor authentication and SMTP password reset.

Panel REST API

11 JSON endpoints covering buckets, keys, permissions, and one-call tenant provisioning — with built-in Swagger UI and an OpenAPI spec.

Self-Updating

A nightly cron job pulls the latest release, runs database migrations, rebuilds caches, and keeps the panel in sync — zero-downtime updates.

A panel you'll actually enjoy using

An elegant Laravel dashboard to monitor storage, manage buckets and keys, and issue API tokens — in light or dark mode, secured with TOTP two-factor authentication.

s3.your-site.test
Johnny web panel — storage dashboard

Dashboard — storage overview & top buckets

Simple by design

A push-based model. Orchestration runs only on your primary VPS. Backup servers just need SSH and disk space.

Primary VPS
S3
Garage S3 API :3900
TLS
Caddy — HTTPS :443
UI
Web Panel — Laravel
RC
Nightly Cron → rclone SFTP
Backup Servers — SFTP
01
server-1
02
server-2

Production-ready from day one

Johnny wraps Garage with everything a production S3 setup needs — TLS, backups, key management, and a REST API — on a single Ubuntu VPS.

  • Automatic Let's Encrypt TLS via Caddy
  • Credentials stored securely under /etc/johnny/
  • Nightly SFTP backups with date-based retention
  • Optional S3-to-S3 replication across nodes
  • 11-endpoint REST API with Swagger UI and OpenAPI spec
  • Ubuntu 24.04 LTS — minimal server requirements

Up and running in minutes

Clone the repo, run the installer, and start storing objects. That's it.

1

Clone the repository

Clone outside /root so the Laravel panel can run as www-data.

$ sudo git clone https://github.com/andreapollastri/johnny /opt/johnny
2

Run the autoinstaller

The interactive wizard installs dependencies, configures Garage, Caddy, rclone, and cron.

$ sudo bash /opt/johnny/scripts/autoinstall.sh
3

Load credentials and go

Your S3 credentials are ready. Use any AWS SDK or S3 client to start working.

$ source /etc/johnny/credentials/default-s3.env
$ aws s3 ls --endpoint-url "$AWS_ENDPOINT_URL"

Powerful, straightforward CLI

Manage storage, keys, and backups with simple commands.

General

johnny version Print installed version
johnny status Garage cluster status
johnny update Update installation

Buckets & Keys

johnny bucket list List all buckets
johnny bucket create Create a new bucket
johnny key list List API keys
johnny key create Create an API key

Backup Targets

johnny backup list List targets & retention
johnny backup create Add a backup target
johnny backup delete Remove a target
johnny backup run Run backup now

Web Panel

install-panel.sh Install the panel
johnny:admin Create admin user
config:cache Rebuild config cache

Manage everything over HTTP

Secured with Laravel Sanctum tokens. Interactive docs at /api/docs, OpenAPI spec at /api/openapi.yaml.

Buckets

GET /api/buckets List all buckets
POST /api/buckets Create a bucket
GET /api/buckets/{bucket} Bucket metadata & keys
DEL /api/buckets/{bucket} Delete an empty bucket

Keys

GET /api/keys List Garage keys
POST /api/keys Create a new key
GET /api/keys/{keyId} Key lookup by id
DEL /api/keys/{keyId} Delete a key

Permissions

POST /api/buckets/{b}/keys Grant key access
DEL /api/buckets/{b}/keys/{k} Revoke key access

Provisioning

POST /api/buckets/provision

Bucket + key + credentials in one call

# Create a Sanctum token
$ php artisan johnny:api-token you@example.com \
    --name=provisioning

# Provision a bucket with a dedicated key
$ curl -sS -X POST \
  "https://s3.your-site.test/api/buckets/provision" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"bucket":"customer-orders"}'
Response · 201 Created
{
  "bucket": "customer-orders",
  "credentials": {
    "alias": "customer-orders-key-123...",
    "access_key_id": "GK...",
    "secret_access_key": "..."
  },
}
s3.your-site.test/api/docs
Johnny Panel API — interactive Swagger UI documentation

Interactive Swagger UI — explore and try every endpoint in the browser

Drop-in S3 disk for Laravel

Johnny is fully compatible with Laravel's S3 filesystem driver. Install the Flysystem adapter, paste the credentials into your .env, and start storing files.

1

Install the S3 driver

$ composer require league/flysystem-aws-s3-v3 "^3.0" --with-all-dependencies
2

Configure your .env

FILESYSTEM_DISK=s3

AWS_ACCESS_KEY_ID=GK....123
AWS_SECRET_ACCESS_KEY=012...XYZ
AWS_DEFAULT_REGION=johnny
AWS_BUCKET=my-bucket
AWS_ENDPOINT=https://s3.my-domain.com
AWS_USE_PATH_STYLE_ENDPOINT=true
3

Use it

Storage::disk('s3')->put('avatars/photo.jpg', $contents);

Works with the default s3 disk in filesystems.php — no custom driver needed. Compatible with Flysystem, AWS SDK for PHP, Intervention Image, and Spatie Media Library. The provisioning API returns these same keys in an env map for automated tenant onboarding.