← All posts

A DigitalOcean Spaces client for Mac that also handles MinIO

DigitalOcean Spaces and MinIO both implement the Amazon S3 API, so a single S3 client on your Mac can work with either, as well as with Amazon S3 itself. What changes between them is four settings: the endpoint, the region, whether the bucket goes in the hostname or the path, and how TLS is set up. This guide gives the right values for a DigitalOcean Spaces client on a Mac, then for a self-hosted MinIO server, and explains the errors you'll see when one of them is off.

The four settings that differ between S3 services

SettingAmazon S3DigitalOcean SpacesMinIO
EndpointBuilt from the region<region>.digitaloceanspaces.comYour server's hostname
RegionWhere the bucket lives, e.g. eu-west-2The data centre slug, e.g. nyc3us-east-1 unless configured otherwise
AddressingBucket in hostnameBucket in hostname (path also works)Bucket in path, unless a domain is configured
TLSPublic certificatePublic certificateWhatever you configure

DigitalOcean Spaces: what a Mac client needs

Endpoint and region

Each Spaces data centre has its own endpoint, named after the region slug: nyc3.digitaloceanspaces.com, ams3.digitaloceanspaces.com, fra1.digitaloceanspaces.com, sgp1.digitaloceanspaces.com and so on. Use the one for the region your bucket was created in; the control panel shows it on the bucket's page.

For the region in the request signature, use the same data centre slug, such as nyc3. Spaces also has a CDN hostname (<bucket>.<region>.cdn.digitaloceanspaces.com) for serving files to browsers. That's not an API endpoint; don't use it in a client.

Access keys

Spaces doesn't use your DigitalOcean API token for S3 requests. Create a Spaces access key in the control panel, which gives you an access key ID and a secret. The secret is shown once, so copy it into your client or password manager before leaving the page. If you can limit the key to the buckets it needs, do; a key that can only reach one bucket can't damage the others.

Addressing

Spaces accepts the bucket in the hostname (my-bucket.nyc3.digitaloceanspaces.com), which is the usual form. Switch to path style only if your bucket name contains dots, because a dotted name in the hostname won't match the wildcard TLS certificate.

DigitalOcean's Spaces documentation lists the current regions and covers bucket-level settings such as CORS and the CDN.

MinIO

MinIO is S3-compatible storage you run yourself, so you choose the settings. Three defaults matter to a client.

Path style is the default

MinIO expects the bucket in the path (minio.example.com/my-bucket/key) unless you've configured a domain for virtual-hosted requests with the MINIO_DOMAIN environment variable. Most clients need path style switched on for MinIO.

The region is us-east-1

Unless you've set a region in MinIO's configuration, it uses us-east-1, and a signature made for a different region fails.

Port and TLS

MinIO listens on port 9000 by default, and serves plain HTTP unless it finds a certificate. You can give MinIO a certificate directly (it looks for public.crt and private.key in its certs directory), but a common setup is a reverse proxy that terminates TLS on port 443 and forwards to MinIO locally. With nginx, the essentials are passing the original Host header, because S3 signatures cover it, and not limiting or buffering request bodies:

server {
    listen 443 ssl;
    server_name minio.example.com;

    ssl_certificate     /etc/letsencrypt/live/minio.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/minio.example.com/privkey.pem;

    client_max_body_size 0;
    proxy_buffering off;
    proxy_request_buffering off;

    location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://127.0.0.1:9000;
    }
}

If the proxy rewrites the Host header, every request fails with a signature mismatch even though the keys are correct.

Setting up Spaces and MinIO in Wharf

Wharf handles Amazon S3 and S3-compatible storage through the same site editor as SFTP and FTP, and its custom endpoint is meant for exactly these services; the editor names DigitalOcean Spaces and MinIO alongside Cloudflare R2. Choose Amazon S3 as the protocol, then:

For Spaces

For MinIO

Wharf always connects to the endpoint over HTTPS on the standard port, and the Endpoint field takes a hostname rather than a host:port pair. For MinIO that means putting it behind TLS on port 443, as in the proxy example above, rather than pointing Wharf at port 9000. The certificate needs to be one your Mac trusts: a public one such as Let's Encrypt, or your own certificate authority added to Keychain Access and marked as trusted.

When you connect, Wharf makes one small listing request to check the keys, region and bucket together, so a mistake shows up immediately. Errors are reported in plain terms: a refused key, for example, produces "Access denied" with a suggestion to check the key and whether it may use this bucket. For anything less obvious, View › Server Log… (⌘⇧K) shows each request and the service's error response, along with the canonical request that was signed, which is the quickest way to spot a proxy changing a header.

Once connected, Spaces and MinIO work like any other site: drag and drop, Quick Look previews, and folder sync. Wharf's S3 support is described on the features page, and the Cloudflare R2 guide covers the third service named in the editor.

Common errors

Object storage also differs from a server in ways no client can hide: folders are key prefixes, renames are a copy and a delete, and there are no Unix permissions. The S3 client guide explains those differences, and the support page covers credentials and the Keychain.