Store media in an object store

By default, Funkwhale stores all media data in the /srv/funkwhale/data/media directory. If you prefer to use an S3-compatible object store, follow the instructions in this guide.

Secure your object store

Before you begin, you need to secure your object store. Many S3-compatible stores list contents in the root by default. This exposes the URLs of your audio files and means that users can bypass authentication.

To prevent listing content, add the following policy to your S3-compatible object store.

{
    "Version": "2012-10-17",
    "Statement": [
        {
        "Action": [
            "s3:GetObject"
        ],
        "Effect": "Allow",
        "Principal": {
            "AWS": [
            "*"
            ]
        },
        "Resource": [
            "arn:aws:s3:::<yourbucketname>/*"
        ],
        "Sid": "Public"
        }
    ]
}

If you’re using awscli, you can store this policy in a /tmp/policy file and apply it using the following command:

aws s3api put-bucket-policy --bucket <yourbucketname> --policy file:///tmp/policy

Update your environment file

To set up S3-compatible storage, fill out the relevant details in the .env file. If you want to serve audio files from the bucket, set PROXY_MEDIA to false.

Environment variables

Internally, Funkwhale uses the django-storages library. See the documentation for more details about environment variables.

AWS_QUERYSTRING_AUTH = False

Whether to include signatures in S3 URLs. Signatures are used to enforce access control.

Defaults to the opposite of PROXY_MEDIA.

AWS_QUERYSTRING_EXPIRE = 3600

The time in seconds before AWS signatures expire. Only takes effect you enable AWS_QUERYSTRING_AUTH

AWS_ACCESS_KEY_ID = 'my_access_key'

Access-key ID for your S3 storage.

AWS_SECRET_ACCESS_KEY = 'my_secret_key'

Secret access key for your S3 storage.

AWS_STORAGE_BUCKET_NAME = 'my_bucket'

Your S3 bucket name.

AWS_S3_CUSTOM_DOMAIN = None

Custom domain for serving your S3 files.

Useful if your provider offers a CDN-like service for your bucket.

Important

The URL must not contain a scheme (AWS_S3_URL_PROTOCOL is automatically prepended) nor a trailing slash.

AWS_S3_URL_PROTOCOL = 'https:'

Protocol to use when constructing the custom domain (see AWS_S3_CUSTOM_DOMAIN) .. important:

It must end with a `:`, remove `//`.
AWS_S3_ENDPOINT_URL = https://minio.mydomain.com

If you use a S3-compatible storage such as minio, set the following variable to the full URL to the storage server.

Examples:

  • https://minio.mydomain.com

  • https://s3.wasabisys.com

AWS_S3_REGION_NAME = eu-west-2

If you’re using Amazon S3 to serve media without a proxy, you need to specify your region name to access files.

Example:

  • eu-west-2

AWS_LOCATION = funkwhale_music

A directory in your S3 bucket where you store files. Use this if you plan to share the bucket between services.

PROXY_MEDIA = True

Whether to proxy audio files through your reverse proxy. We recommend you leave this enabled to enforce access control.

If you’re using S3 storage with AWS_QUERYSTRING_AUTH enabled, it’s safe to disable this setting.

Set up your reverse proxy

Note

Serving files from object storage is not currently supported on Apache deployments.

Serving files from an object store requires some changes to the reverse proxy.

  1. Open your Nginx configuration file in an editor.

    sudo nano /etc/nginx/sites-available/funkwhale.template
    
    nano /srv/funkwhale/nginx/funkwhale.template
    
  2. Comment out the location /_protected/media/ block by adding a # to the start of each line.

    #   location /_protected/media/ {
    #        internal;
    #        alias   ${MEDIA_ROOT};
    #    }
    
  3. Uncomment the location ~ /_protected/media/(.+) block by removing the # from the start of each line.

       location ~ /_protected/media/(.+) {
             internal;
             proxy_set_header Authorization "";
             proxy_pass $1;
       }
    
  4. Add your S3 store URL to the img-src and media-src headers.

    add_header Content-Security-Policy "...img-src 'self' https://<your-s3-URL> data:;...media-src https://<your-s3-URL> 'self' data:";
    
  5. Test your Nginx configuration.

    sudo nginx -t
    
  6. Restart Funkwhale and Nginx to pick up the changes.

    sudo systemctl restart funkwhale.target
    sudo systemctl restart nginx
    
    docker compose restart
    sudo systemctl restart nginx
    

That’s it! Files are now uploaded to and stored from your S3 bucket.

Troubleshooting

No Resolver Found

You may see the following error when streaming music from your S3-compatible store:

[error] 2832#2832: *1 no resolver defined to resolve [address] client: [IP], server: [servername], request: "GET API request", host: "[your_domain]", referrer: "[your_domain/library]"

This happens when the Nginx config is unable to use your server’s DNS resolver. We’re still looking into this issue. You can work around this by adding a resolver to the location ~/_protected/media/(.+) block.

location ~ /_protected/media/(.+) {
    resolver 1.1.1.1;
    internal;
    proxy_set_header Authorization "";
    proxy_pass $1;
}