RustFS - Installing and Configuring S3-Compatible Storage
Greetings!

In this article, we will look at installing and basic configuration of RustFS - S3-compatible object storage that we will deploy on a Linux server using Docker Compose.

Goal: get our own S3 endpoint, a web console, a valid HTTPS connection (via Caddy + Let’s Encrypt), and check that all this works with the excellent rclone and restic utilities 😌.

Input data

To configure our installation, it is assumed that we already have 📃:

Installing RustFS S3 storage

Connect to the rustfs.r4ven.me server using SSH and switch to the root account using sudo:

BASH
ssh ivan@rustfs.r4ven.me

sudo -i
Click to expand and view more

Create the project directory and restrict access to it using the chmod command:

BASH
mkdir -vp /etc/compose/rustfs && cd /etc/compose/rustfs

chmod 700 /etc/compose
Click to expand and view more

Now create the compose file, for example using the vim editor:

BASH
vim ./compose.yaml
Click to expand and view more

Fill it with:

YAML
---
# https://github.com/rustfs/rustfs
# https://caddyserver.com/docs/running#docker-compose

volumes:
  rustfs:
    name: rustfs
  caddy:
    name: caddy

services:
  rustfs:
    image: docker.io/rustfs/rustfs:1.0.0-beta.8
    container_name: rustfs
    restart: unless-stopped
    stop_grace_period: 30s
    cpus: 1
    mem_limit: 1G
    hostname: rustfs
    user: "root:root"
    env_file: ./.env
    healthcheck:
      test:
        ["CMD", "sh", "-c", "curl -f http://127.0.0.1:9000/health && curl -f http://127.0.0.1:9001/rustfs/console/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    expose:
      - "9000" # S3 API port
      - "9001" # Console port
    volumes:
      - rustfs:/data/
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro

  caddy:
    image: docker.io/caddy:2.9.1-alpine
    depends_on:
      rustfs:
        condition: service_healthy
    container_name: caddy
    restart: unless-stopped
    stop_grace_period: 30s
    cpus: 1
    mem_limit: 512M
    hostname: caddy
    env_file: ./.env
    environment:
      TZ: Europe/Moscow
    configs:
      - source: caddy_config
        target: /etc/caddy/Caddyfile
    command: caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
    healthcheck:
      test: ["CMD", "sh", "-c", "wget --no-verbose --tries=1 --spider https://${RUSTFS_DOMAIN}:443/health && wget --no-verbose --tries=1 --spider https://${RUSTFS_CONSOLE_DOMAIN}:443/rustfs/console/auth/login"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    ports:
      - "80:80/tcp"
      - "443:443/tcp"
      - "443:443/udp"
    volumes:
      - caddy:/data/
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro

configs:
  caddy_config:
    content: |
      {
          email ${ACME_EMAIL}
          admin off
      }

      ${RUSTFS_DOMAIN} {
          reverse_proxy rustfs:9000

          header {
              Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
              X-Content-Type-Options "nosniff"
              X-Frame-Options "DENY"
              Referrer-Policy "no-referrer"
          }
      }

      ${RUSTFS_CONSOLE_DOMAIN} {
          reverse_proxy rustfs:9001

          header {
              Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
              X-Content-Type-Options "nosniff"
              X-Frame-Options "DENY"
              Referrer-Policy "no-referrer"
          }
      }
Click to expand and view more

This file describes two services: rustfs and caddy. The first one is clear enough, but it is worth adding a bit of information about the second one.

Now create the env file:

BASH
vim ./.env
Click to expand and view more

Fill it with:

INI
# https://docs.rustfs.com/installation/docker/#complete-parameter-configuration-example

TZ=Europe/Moscow

ACME_EMAIL=kar-kar@r4ven.me
RUSTFS_DOMAIN=rustfs.r4ven.me
RUSTFS_CONSOLE_DOMAIN=rustfs-console.r4ven.me

# RUSTFS_UID="root"
# RUSTFS_GID="root"
# RUSTFS_VOLUMES=/data/rustfs{0..3} # Define 4 storage volumes
RUSTFS_ADDRESS=0.0.0.0:9000
RUSTFS_CONSOLE_ENABLE=true
RUSTFS_CONSOLE_ADDRESS=0.0.0.0:9001
RUSTFS_CORS_ALLOWED_ORIGINS=https://rustfs-console.r4ven.me
RUSTFS_CONSOLE_CORS_ALLOWED_ORIGINS=https://rustfs-console.r4ven.me
RUSTFS_ACCESS_KEY=
RUSTFS_SECRET_KEY=
RUSTFS_OBS_LOGGER_LEVEL=info
Click to expand and view more

We do not create Caddyfile as a separate file. Docker Compose passes it into the container via the configs parameter, and substitutes environment variables while processing the compose file. Caddy will store Let’s Encrypt certificates and other files in a docker volume named caddy.

Set the “login” and generate the “password”:

BASH
sed -iE "s/^RUSTFS_ACCESS_KEY=.*/RUSTFS_ACCESS_KEY=ivan/" ./.env

sed -iE "s/^RUSTFS_SECRET_KEY=.*/RUSTFS_SECRET_KEY=$(openssl rand -hex 32)/" ./.env
Click to expand and view more

Now start the stack:

BASH
docker compose up -d && docker compose logs -f
Click to expand and view more

Check it:

BASH
docker compose ps

docker volume ls | grep -E "rustfs|caddy"

ls -lR /var/lib/docker/volumes/caddy/_data/caddy/
Click to expand and view more

Immediately configure autostart using Systemd:

BASH
cat > ./rustfs.service << EOF
[Unit]
Description=RustFS S3 service
Requires=docker.service
After=docker.service

[Service]
Restart=always
RestartSec=5
User=root
Group=root
WorkingDirectory=/etc/compose/rustfs
ExecStart=/usr/bin/docker compose up --remove-orphans
ExecStop=/usr/bin/docker compose down

[Install]
WantedBy=multi-user.target
EOF
Click to expand and view more
BASH
chmod 600 ./rustfs.service

ln -s $(realpath ./rustfs.service) /etc/systemd/system

systemctl daemon-reload

systemctl enable --now rustfs

systemctl status rustfs
Click to expand and view more

Now the rustfs service can be managed using systemctl:

BASH
systemctl stop rustfs
systemctl start rustfs
systemctl restart rustfs
systemctl status rustfs
Click to expand and view more

Configuring RustFS

Open a web browser and enter the address:

BASH
https://rustfs-console.r4ven.me
Click to expand and view more

We will see the login window for the S3 storage management console. Pay attention to the secure connection:

Use the credentials we generated in the previous step to log in:

BASH
grep -E 'RUSTFS_ACCESS_KEY|RUSTFS_SECRET_KEY' /etc/compose/rustfs/.env
Click to expand and view more

Creating buckets

Below I will show the bucket creation process:

On the “Browser” tab, click “Create bucket”:

In the popup window, set its name, for example app1, set the quota (storage size limit), and click “Create”:

In the bucket list, we will see the one we created:

Creating access credentials

Next, we will create access credentials for the bucket for client connections. Using a separate account for performing various bucket operations via the API is considered good practice.

Go to “Users” –> “Add user”:

Here, specify the name, in our example backup, and set a password for it. In the “Policy” section, select readwrite and click “Submit”:

After creation, click “Edit” next to the new user:

Go to the “Access keys” tab and click “Add access keys”:

Here, specify an arbitrary name and description. You can also set the key expiration date. If you do not select a date, the key will be active indefinitely. Complete creation with the “Submit” button:

A window with the new access key and secret key will appear. Be sure to save them, maybe even export them, because you will not be able to view them again:

In our example, the data is as follows:

You can create many such keys for one user with different access policies.

Checking S3 operation with Rclone

To test our object storage, we will use the excellent rclone utility, about which I recently wrote an article on mounting remote storage.

The utility is available in standard Linux repositories. Install it and create a config using the shell here doc mechanism. Do not forget to substitute your own values for endpoint, access_key_id (access key), and secret_access_key (secret key):

BASH
apt install -y rclone

mkdir -vp ~/.config/rclone

cat > ~/.config/rclone/rclone.conf << EOF
[rustfs]
type = s3
provider = Minio
endpoint = https://rustfs.r4ven.me
access_key_id = haRQaZRE9OGlUULAE2EQ
secret_access_key = QkgSFIG03saT2l7tnIF7OSUuxIwmKlx6RabFOs9i
EOF
Click to expand and view more

Check access to the storage:

BASH
rclone lsd rustfs:
Click to expand and view more

If you see the name of your bucket, the connection is successful:

Now create a “directory” inside the bucket and copy a tar archive with the contents of the /etc directory there using the stream redirection mechanism:

BASH
tar -czf - /etc | rclone rcat rustfs:app1/rclone/backup_etc_$(date '+%F').tar.gz

rclone ls rustfs:app1/rclone
Click to expand and view more

You can restore files from S3 using rclone like this:

BASH
mkdir -vp /tmp/restore/rclone

# Archive in one file
rclone copy rustfs:app1/rclone/backup_etc_2026-06-16.tar.gz /tmp/restore/rclone

# Unzip immediately
rclone cat rustfs:app1/rclone/backup_etc_2026-06-16.tar.gz | tar -xzf - -C /tmp/restore/rclone

ls -l /tmp/restore/rclone
Click to expand and view more

Checking S3 operation with Restic

Another popular S3 use case is backups with another excellent utility, restic.

restic is also available in standard Linux repositories. Its configuration method is somewhat different from the same rclone. All parameters are set in environment variables, which must be loaded for each terminal session.

Let’s install restic and save all the required parameters to an env file so they can be loaded all at once:

BASH
apt install -y restic

mkdir -vp ~/.config/restic

cat > ~/.config/restic/env << EOF
export AWS_ACCESS_KEY_ID="haRQaZRE9OGlUULAE2EQ"  
export AWS_SECRET_ACCESS_KEY="QkgSFIG03saT2l7tnIF7OSUuxIwmKlx6RabFOs9i"  
export AWS_DEFAULT_REGION="us-east-1"  
export RESTIC_REPOSITORY="s3:https://rustfs.r4ven.me/app1/restic"
export RESTIC_PASSWORD="12345678"
EOF

source ~/.config/restic/env
Click to expand and view more

Now let’s initialize the restic repository and create a backup of the /etc directory, as we did earlier with rclone, but now without tar:

BASH
restic init

restic backup /etc

restic stats

restic snapshots
Click to expand and view more

View the repository contents:

BASH
restic ls latest | less
Click to expand and view more

You can restore files to the specified directory from the latest backup like this:

BASH
restic restore latest --target /tmp/restore

ls -l /tmp/restore
Click to expand and view more

Afterword

So, we have configured our own S3-compatible RustFS storage, protected behind the Caddy reverse proxy. For a small personal server, backups, test buckets, and all kinds of internal services - this is quite an excellent option 👍.

The RustFS project itself still looks young, so I would recommend keeping an eye on updates and using it in production with a bit more caution than the same MinIO.

Thank you for reading. And remember, admins are divided into two types: those who make backups, and those who definitely will. All the best!

References

Copyright Notice

Author: Иван Чёрный

Link: https://r4ven.me/en/storage/rustfs-ustanovka-i-nastroyka-s3-sovmestimogo-hranilishcha/

License: CC BY-NC-SA 4.0

Использование материалов блога разрешается при условии: указания авторства/источника, некоммерческого использования и сохранения лицензии.

Start searching

Enter keywords to search articles

↑↓
ESC
⌘K Shortcut