Recently I wanted to host my Pangolin instance to expose some services to the internet.
Instead of looking at VPS options like AWS Lightsail, Vultr, etc., I went to Lowendtalk.
Lowendtalk is a great place to find some crazy VPS deals, and I ended up buying too many VPSes for the purpose.

Eventually I found a suitable VPS instance, which left some of the other VPSes idle.
To make use of them, I used a static side project as a test.

Why not MinIO?

Features are being deleted from the Community Edition ,
which is a pretty bad move, especially when so many people ended up hard-forking it.

So, Garage is my alternative

Garage is an open-source S3-compatible object storage written in Rust.
It is easy to set up for lightweight use. One downside is that there is no native web UI,
but for Garage v1 there is a web UI , just not for v2.

Setup Time

I set it up as a Docker stack: Garage for object storage and Caddy for the reverse proxy. Stack:

My Garage configuration (garage.toml) has slight changes from the quickstart
In this config, there are two ports that will be used in the Caddy configuration:

  • 3900 is the port hosting the S3 API
  • 3902 is the port hosting the S3 static website

Caddy & Caddyfile

I use Caddy as the reverse proxy host because it is

  • Easy to set up
  • Minimal configuration for just reverse proxy
  • Automatically acquires and renews Let’s Encrypt certificates with no additional config
  • Small image size

The Caddyfile is very simple, just a few lines:

You need two domains for this to work:

  1. The S3 endpoint endpoint.of.your.s3.domain.tld for your tools to upload the site
  2. The website endpoint one.of.your.exposed.web.domain.ltd for users to access it from a browser

Setup Time (Cont.)

After running docker compose up, let’s configure Garage.
Find your server ID first by running:

docker exec -it garage /garage status
ID Hostname Address
2e6598413da74cdb cfb62636e477 127.0.0.1:3901

After finding the ID, you can create a layout like this (this example assigns 30GB of disk):

docker exec -it garage /garage layout assign -z dc1 -c 30G 2e6598413da74cdb
docker exec -it garage /garage layout apply --version 1

Create your access key and save it for later use:

docker exec -it garage /garage key create your-key-name
==== ACCESS KEY INFORMATION ====
Key ID: GK………….
Key name: your-key-name
Secret key: …………..

Setup the bucket to expose as website

For each static website, do the following steps to create website buckets.
Set the bucket name to the domain name of the website.

docker exec -it garage /garage bucket create one.of.your.exposed.web.domain.ltd
docker exec -it garage /garage bucket website --allow one.of.your.exposed.web.domain.ltd

After creating the bucket, assign the key and permissions to make it accessible.

docker exec -it garage /garage bucket allow --read --write --owner one.of.your.exposed.web.domain.ltd --key your-key-name

And that’s it for the website bucket configuration.

Upload your static site using awscli

Create a .awsrc for Garage and source it when needed. Then you can upload the website with just one command:

aws s3 cp your-static-site-folder s3://one.of.your.exposed.web.domain.ltd --recursive

For Garage v1 users using awscli
Make sure you use the --checksum-algorithm SHA256 flag to upload your object, as awscli doesn’t do algorithm fallback checks.

aws s3 cp your-static-site-folder s3://one.of.your.exposed.web.domain.ltd --recursive --checksum-algorithm SHA256

And sure enough, I could access my side project from the VPS once the setup was done.