Skip to content

S3 / RustFS / MinIO / R2 ​

Driver: s3

This storage driver stores the cache in a S3 compatible storage, e.g. AWS S3 or RustFS.

Configuration ​

docker-compose RustFS example ​

docker-compose.yml
yaml
version: '3.9'

services:
  cache-server:
    image: ghcr.io/falcondev-oss/github-actions-cache-server:latest
    ports:
      - '3000:3000'
    environment:
      API_BASE_URL: http://localhost:3000

      STORAGE_DRIVER: s3
      STORAGE_S3_BUCKET: gh-actions-cache

      AWS_ACCESS_KEY_ID: access_key
      AWS_SECRET_ACCESS_KEY: secret_key
      AWS_ENDPOINT_URL: http://rustfs:9000
    volumes:
      - cache-data:/app/.data

  rustfs:
    image: rustfs/rustfs:latest
    ports:
      - '9000:9000'
      - '9001:9001'
    environment:
      RUSTFS_ACCESS_KEY: access_key
      RUSTFS_SECRET_KEY: secret_key
    volumes:
      - rustfs-data:/data

volumes:
  cache-data:
  rustfs-data:

docker-compose AWS S3 example ​

This example assumes that credentials are being provided by the environment, e.g. via an instance profile or EKS IRSA.

docker-compose.yml
yaml
version: '3.9'

services:
  cache-server:
    image: ghcr.io/falcondev-oss/github-actions-cache-server:latest
    ports:
      - '3000:3000'
    environment:
      API_BASE_URL: http://localhost:3000

      STORAGE_DRIVER: s3
      STORAGE_S3_BUCKET: gh-actions-cache

    volumes:
      - cache-data:/app/.data

volumes:
  cache-data:

Environment Variables ​

The only required S3-related environment variables are STORAGE_DRIVER: s3 and STORAGE_S3_BUCKET. The rest of the environment variables are optional and depend on your S3-compatible storage provider.

The server picks up AWS credentials from the environment: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY (with AWS_SESSION_TOKEN), a web identity token (EKS IRSA), ECS task credentials or EC2 instance metadata. Outside of AWS, the access key variables authenticate with S3-compatible storage, as seen in the RustFS example above. Shared credential files and AWS_PROFILE are not supported.

Common environment variables are listed below. For a full list, see AmazonS3Builder::from_env.

STORAGE_S3_BUCKET ​

Example: gh-actions-cache

The name of the S3 bucket used for storage. This environment variable is always required.

AWS_REGION ​

Example: us-east-1

Defaults to us-east-1. This has no effect if you are using a non-AWS S3-compatible storage provider, such as RustFS.

AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY ​

Example: AWS_ACCESS_KEY_ID: access_keyAWS_SECRET_ACCESS_KEY: secret_key

This is the access key/secret key used to authenticate with S3-compatible storage. If required to authenticate with your provider, these should be provided by the provider.

AWS_ENDPOINT_URL ​

Example: http://rustfs:9000

This is the endpoint URL for the S3-compatible storage. This is only required if you are using a non-AWS S3-compatible storage provider, such as RustFS.

STORAGE_S3_SOCKET_TIMEOUT_MS ​

  • Default: 10000

How long a request to S3 may go without making progress before it fails. 0 disables it.

Minimal IAM permissions ​

The cache server only ever touches objects under the gh-actions-cache/ prefix in the bucket. These are all the actions it performs:

ActionUsed for
s3:ListBucketStartup bucket check, listing/counting cache objects
s3:GetObjectDownloading cache entries, existence checks
s3:PutObjectUploading cache entries, merging parts
s3:AbortMultipartUploadCleaning up failed multipart uploads
s3:DeleteObjectCache cleanup and abandoned uploads

A minimal policy, scoped to the bucket and prefix (replace YOUR_BUCKET):

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "github-actions-cache-server-bucket",
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": "arn:aws:s3:::YOUR_BUCKET"
    },
    {
      "Sid": "github-actions-cache-server-objects",
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:AbortMultipartUpload", "s3:DeleteObject"],
      "Resource": "arn:aws:s3:::YOUR_BUCKET/gh-actions-cache/*"
    }
  ]
}

Parts are uploaded through presigned URLs, which the server signs with its own credentials. If they can't sign, uploads fall back to multipart.

Incomplete multipart uploads ​

A server killed mid-upload or mid-merge leaves an incomplete multipart upload that S3 keeps and bills. Add a lifecycle rule that aborts them:

json
{
  "Rules": [
    {
      "ID": "abort-incomplete-uploads",
      "Status": "Enabled",
      "Filter": { "Prefix": "gh-actions-cache/" },
      "AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 1 }
    }
  ]
}