Instance configuration
General configuration is achieved using two type of settings:
Environment variables
Those are located in your .env
file, which you should have created
during installation. A full list of available variables is given below.
Options from this file are heavily commented, and usually target lower level and technical aspects of your instance, such as database credentials.
Note
You should restart all Funkwhale processes when you change the values on environment variables:
sudo systemctl restart funkwhale.target
Note
Some characters are unsafe to use in configuration variables that are URLs, such as the user and password in the database and SMTP sections. If those variables contain such characters, they must be urlencoded, for instance using the following command:
python3 -c 'import urllib.parse; print(urllib.parse.quote_plus("p@ssword"))
See as well https://github.com/joke2k/django-environ#using-unsafe-characters-in-urls
Instance settings
These settings are stored in the database and do not require a restart of your instance after modification. They typically relate to higher level configuration, such your instance description, signup policy and so on.
You can edit those settings directly from the web application, assuming
you have the required permissions. The URL is /manage/settings
, and
you will also find a link to this page in the sidebar.
If you plan to use acoustid and external imports (e.g. with the YouTube backends), you should edit the corresponding settings in this interface.
Note
If you have any issue with the web application, a management interface is also available for those settings from Django’s administration interface. It’s less user friendly, though, and we recommend you use the web app interface whenever possible.
The URL should be /api/admin/dynamic_preferences/globalpreferencemodel/
(prepend your domain in front of it, of course).
Configuration reference
Pod
- FUNKWHALE_HOSTNAME
Hostname of your Funkwhale pod, e.g.
mypod.audio
- FUNKWHALE_PROTOCOL = ''
Protocol end users will use to access your pod, either
http
orhttps
.
Database and redis
- DATABASE_URL
URL to connect to the PostgreSQL database. Examples:
postgresql://funkwhale@:5432/funkwhale
postgresql://<user>:<password>@<host>:<port>/<database>
postgresql://funkwhale:passw0rd@localhost:5432/funkwhale_database
- DB_CONN_MAX_AGE = 300
Max time, in seconds, before database connections are closed.
- CACHE_URL
URL to your redis server. Examples:
redis://<host>:<port>/<database>
redis://127.0.0.1:6379/0
redis://:password@localhost:6379/0
for password auth (the extra semicolon is important) -
redis:///run/redis/redis.sock?db=0
over unix socketsNote
If you want to use Redis over unix sockets, you’ll also need to update
CELERY_BROKER_URL
Accounts and registration
- ACCOUNT_EMAIL_VERIFICATION_ENFORCE
Determine wether users need to verify their e-mail address before using the service. Enabling this can be useful to reduce spam or bots accounts, however, you’ll need to configure a mail server so that your users can receive the verification e-mails, using
EMAIL_CONFIG
.Note that regardless of the setting value, superusers created through the command line will never require verification.
Note that regardless of the setting value, superusers created through the command line will never require verification.
- USERS_INVITATION_EXPIRATION_DAYS
Expiration delay, in days, for user invitations.
- DISABLE_PASSWORD_VALIDATORS
Wether to disable password validators (length, common words, similarity with username…) used during regitration.
- ACCOUNT_USERNAME_BLACKLIST
List of usernames that will be unavailable during registration, given as a list of strings.
- AUTH_LDAP_ENABLED
Wether to enable LDAP authentication.
See /installation/ldap for more information.
Media storage and serving
- MEDIA_URL = https://mypod.audio/media/
URL where media files are served. The default value should work fine on most configurations, but could can tweak this if you are hosting media files on a separate domain, or if you host Funkwhale on a non-standard port.
- MEDIA_ROOT = /srv/funkwhale/data/media
Path where media files (such as album covers or audio tracks) are stored on your system. Ensure this directory actually exists.
- PROXY_MEDIA = true
Wether to proxy audio files through your reverse proxy. It’s recommended to keep this on, as a way to enforce access control, however, if you’re using S3 storage with
AWS_QUERYSTRING_AUTH
, it’s safe to disable it.
- EXTERNAL_MEDIA_PROXY_ENABLED = True
Wether to proxy attachment files hosted on third party pods and and servers. Keeping this to true is recommended, to reduce leaking browsing information of your users, and reduce the bandwidth used on remote pods.
- ATTACHMENTS_UNATTACHED_PRUNE_DELAY = true
Delay in seconds before uploaded but unattached attachements are pruned from the system.
- REVERSE_PROXY_TYPE = 'nginx'
Depending on the reverse proxy used in front of your funkwhale instance, the API will use different kind of headers to serve audio files
Allowed values:
nginx
,apache2
- PROTECT_FILES_PATH = '/_protected'
Which path will be used to process the internal redirection to the reverse proxy DO NOT put a slash at the end.
You shouldn’t have to tweak this.
Audio acquisition
- MUSIC_DIRECTORY_PATH = None
The path on your server where Funkwhale can import files using in-place import. It must be readable by the webserver and Funkwhale api and worker processes.
On docker installations, we recommend you use the default of
/music
for this value. For non-docker installation, you can use any absolute path./srv/funkwhale/data/music
is a safe choice if you don’t know what to use.Note
This path should not include any trailing slash.
Warning
You need to adapt your reverse proxy configuration to serve the directory pointed by
MUSIC_DIRECTORY_PATH
on/_protected/music
URL.
- MUSIC_DIRECTORY_SERVE_PATH = None
Default:
MUSIC_DIRECTORY_PATH
When using Docker, the value of
MUSIC_DIRECTORY_PATH
in your containers may differ from the real path on your host. Assuming you have the following directive in yourdocker-compose.yml
file:volumes: - /srv/funkwhale/data/music:/music:ro
Then, the value of
MUSIC_DIRECTORY_SERVE_PATH
should be/srv/funkwhale/data/music
. This must be readable by the webserver.On non-docker setup, you don’t need to configure this setting.
Note
This path should not include any trailing slash.
S3 Storage
- AWS_QUERYSTRING_AUTH = False
Whether to include signatures in S3 urls, as a way to enforce access-control.
Defaults to the inverse of
PROXY_MEDIA
.
- AWS_QUERYSTRING_EXPIRE = 3600
Expiration delay, in seconds, of signatures generated when
AWS_QUERYSTRING_AUTH
is enabled.
- 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'
Bucket name of your S3 storage.
- AWS_S3_CUSTOM_DOMAIN = None
Custom domain to use for your S3 storage.
- AWS_S3_ENDPOINT_URL = None
If you use a S3-compatible storage such as minio, set the following variable to the full URL to the storage server. Example:
https://minio.mydomain.com
https://s3.wasabisys.com
- AWS_S3_REGION_NAME = None
If you are using Amazon S3 to serve media directly, you will need to specify your region name in order to access files.
Example:
eu-west-2
- AWS_LOCATION = ''
An optional bucket subdirectory were you want to store the files. This is especially useful if you plan to use share the bucket with other services.
API configuration
- THROTTLING_ENABLED = True
Wether to enable throttling (also known as rate-limiting). Leaving this enabled is recommended especially on public pods, to improve the quality of service.
- THROTTLING_RATES = {'anonymous-create': {'description': 'Anonymous POST requests', 'rate': '1000/day'}, 'anonymous-destroy': {'description': 'Anonymous DELETE requests on resource detail', 'rate': '1000/day'}, 'anonymous-list': {'description': 'Anonymous GET requests on resource lists', 'rate': '10000/day'}, 'anonymous-oauth-app': {'description': 'Anonymous OAuth app creation', 'rate': '10/day'}, 'anonymous-reports': {'description': 'Anonymous report submission', 'rate': '10/day'}, 'anonymous-retrieve': {'description': 'Anonymous GET requests on resource detail', 'rate': '10000/day'}, 'anonymous-update': {'description': 'Anonymous PATCH and PUT requests on resource detail', 'rate': '1000/day'}, 'anonymous-wildcard': {'description': 'Anonymous requests not covered by other limits', 'rate': '1000/h'}, 'authenticated-create': {'description': 'Authenticated POST requests', 'rate': '1000/hour'}, 'authenticated-destroy': {'description': 'Authenticated DELETE requests on resource detail', 'rate': '500/hour'}, 'authenticated-list': {'description': 'Authenticated GET requests on resource lists', 'rate': '10000/hour'}, 'authenticated-oauth-app': {'description': 'Authenticated OAuth app creation', 'rate': '10/hour'}, 'authenticated-reports': {'description': 'Authenticated report submission', 'rate': '100/day'}, 'authenticated-retrieve': {'description': 'Authenticated GET requests on resource detail', 'rate': '10000/hour'}, 'authenticated-update': {'description': 'Authenticated PATCH and PUT requests on resource detail', 'rate': '1000/hour'}, 'authenticated-wildcard': {'description': 'Authenticated requests not covered by other limits', 'rate': '2000/h'}, 'fetch': {'description': 'Fetch remote objects', 'rate': '200/d'}, 'login': {'description': 'Login', 'rate': '30/hour'}, 'oauth-authorize': {'description': 'OAuth app authorization', 'rate': '100/hour'}, 'oauth-revoke-token': {'description': 'OAuth token deletion', 'rate': '100/hour'}, 'oauth-token': {'description': 'OAuth token creation', 'rate': '100/hour'}, 'password-change': {'description': 'Password change (when authenticated)', 'rate': '20/h'}, 'password-reset': {'description': 'Password reset request', 'rate': '20/h'}, 'password-reset-confirm': {'description': 'Password reset confirmation', 'rate': '20/h'}, 'signup': {'description': 'Account creation', 'rate': '10/day'}, 'subsonic': {'description': 'All subsonic API requests', 'rate': '2000/hour'}, 'verify-email': {'description': 'Email address confirmation', 'rate': '20/h'}}
Throttling rates for specific endpoints and features of the app. You can tweak this if you are encountering to severe rate limiting issues or, on the contrary, if you want to reduce the consumption on some endpoints.
Example:
signup=5/d,password-reset=2/d,anonymous-reports=5/d
- ADMIN_URL = '^api/admin/'
Path to the Django admin area.
Examples:
^api/admin/
^api/mycustompath/
- EXTERNAL_REQUESTS_VERIFY_SSL = True
Wether to enforce HTTPS certificates verification when doing outgoing HTTP requests (typically with federation). Disabling this is not recommended.
- EXTERNAL_REQUESTS_TIMEOUT = 10
Default timeout for external requests.
Federation
- FEDERATION_OBJECT_FETCH_DELAY = 4320
Delay, in minutes, before a remote object will be automatically refetched when accessed in the UI.
- FEDERATION_DUPLICATE_FETCH_DELAY = 3000
Delay, in seconds, between two manual fetch of the same remote object.
Metadata
- TAGS_MAX_BY_OBJ = 30
Maximum number of tags that can be associated with an object. Extra tags will be ignored.
- MUSICBRAINZ_HOSTNAME = 'musicbrainz.org'
Use this setting to change the MusicBrainz hostname, for instance to use a mirror. The hostname can also contain a port number.
Example:
mymusicbrainz.mirror
localhost:5000
- MUSICBRAINZ_CACHE_DURATION = 300
How long to cache MusicBrainz results, in seconds.
Channels and podcasts
- PODCASTS_RSS_FEED_REFRESH_DELAY = 86400
Delay, in seconds, between two fetch of RSS feeds.
Reducing this mean you’ll receive new episodes faster, but will require more resources.
- PODCASTS_RSS_FEED_MAX_ITEMS = 250
Maximum number of RSS items to load in each podcast feed.
- PODCASTS_THIRD_PARTY_VISIBILITY = 'me'
By default, only people who subscribe to a podcast RSS will have access to their episodes.
Switch to “instance” or “everyone” to change that.
Changing it only affect new podcasts.
Subsonic
- SUBSONIC_DEFAULT_TRANSCODING_FORMAT = 'mp3'
Default format for transcoding when using Subsonic API.
Email configuration
- EMAIL_CONFIG = consolemail://
SMTP configuration for sending e-mails. Possible values:
EMAIL_CONFIG=consolemail://
: output e-mails to console (the default)EMAIL_CONFIG=dummymail://
: disable e-mail sending completely
On a production instance, you’ll usually want to use an external SMTP server:
EMAIL_CONFIG=smtp://user:password@youremail.host:25
EMAIL_CONFIG=smtp+ssl://user:password@youremail.host:465
EMAIL_CONFIG=smtp+tls://user:password@youremail.host:587
Note
If
user
orpassword
contain special characters (eg.noreply@youremail.host
asuser
), be sure to urlencode them, using for example the command:python3 -c 'import urllib.parse; print(urllib.parse.quote_plus ("noreply@youremail.host"))'
(returnsnoreply%40youremail.host
)
- DEFAULT_FROM_EMAIL = Funkwhale <noreply@yourdomain>
Name and e-mail address used to send system e-mails.
Default:
Funkwhale <noreply@yourdomain>
Note
Both the forms
Funkwhale <noreply@yourdomain>
andnoreply@yourdomain
work.
- EMAIL_SUBJECT_PREFIX = '[Funkwhale] '
Subject prefix for system e-mails.
Other settings
- INSTANCE_SUPPORT_MESSAGE_DELAY = 15
Delay after signup, in days, before the “support your pod” message is shown.
- FUNKWHALE_SUPPORT_MESSAGE_DELAY = 15
Delay after signup, in days, before the “support Funkwhale” message is shown.
- MIN_DELAY_BETWEEN_DOWNLOADS_COUNT = 21600
Minimum required period, in seconds, for two downloads of the same track by the same IP or user to be recorded in statistics.
- MARKDOWN_EXTENSIONS = ['nl2br', 'extra']
List of markdown extensions to enable.
- LINKIFIER_SUPPORTED_TLDS = ['audio']
Additional TLDs to support with our markdown linkifier.
User permissions
Funkwhale’s permission model works as follows:
Anonymous users cannot do anything unless configured specifically;
Logged-in users can use the application, but cannot do things that affect the whole instance;
Superusers can do anything.
To make things more granular and allow some delegation of responsibility, superusers can grant specific permissions to specific users. Available permissions are:
Manage instance-level settings: users with this permission can edit instance settings as described in Instance settings;
Manage library: users with this permission can import new music in the instance;
Manage library federation: users with this permission can ask to federate with other instances, and accept/deny federation requests from other instances.
There is no dedicated interface to manage users permissions, but superusers
can login on the Django’s admin at /api/admin/
and grant permissions
to users at /api/admin/users/user/
.
Front-end settings
We offer a basic mechanism to customize the behavior and look and feel of Funkwhale’s Web UI.
To use any of the options below, you will need to create a custom JSON configuration file and serve it
on https://yourinstanceurl/settings.json
.
On typical deployments, this url returns a 404 error, which is simply ignored.
Set-up
First, create the settings file:
cd /srv/funkwhale/
# create a directory for your configuration file
# you can use a different name / path of course
mkdir custom
# populate the configuration file with default values
cat <<EOF > custom/settings.json
{
"additionalStylesheets": [],
"defaultServerUrl": null
}
EOF
Once the settings.json
file is created, you will need to serve it from your reverse proxy.
If you are using nginx, add the following snippet to your vhost configuration:
location /settings.json {
alias /srv/funkwhale/custom/settings.json;
}
On Apache, add the following to your vhost configuration:
Alias /settings.json /srv/funkwhale/custom/settings.json
Then, reload your reverse proxy.
At this point, visiting https://yourinstanceurl/settings.json
should serve the content
of the settings.json file.
Warning
The settings.json file must be a valid JSON file. If you have any issue, try linting the file with a tool such as https://github.com/zaach/jsonlint to detect potential syntax issues.
Available configuration options
Your settings.json
can contain the following options:
Name |
Type |
Example value |
Description |
|
Array of URLs |
|
A list of stylesheets URL (absolute or relative) that the web UI should load. see the “Theming” section below for a detailed explanation |
|
URL |
|
The URL of the API server this front-end should connect with. If null, the UI will use the value of VUE_APP_INSTANCE_URL (specified during build) or fallback to the current domain |
Missing options or options with a null
value in the settings.json
file are ignored.
Theming
To theme your Funkwhale instance, you need:
A CSS file for your theme, that can be loaded by the front-end;
To update the value of
additionalStylesheets
in your settings.json file to point to your CSS file URL.
cd /srv/funkwhale/custom
nano settings.json
# append
# "additionalStylesheets": ["/front/custom/custom.css"]
# to the configuration or replace the existing value, if any
# create a basic theming file changing the background to red
cat <<EOF > custom.css
body {
background-color: red;
}
EOF
The last step to make this work is to ensure your CSS file is served by the reverse proxy.
On nginx, add the following snippet to your vhost config:
location /custom {
alias /srv/funkwhale/custom;
}
On Apache, use the following:
Alias /custom /srv/funkwhale/custom
<Directory "/srv/funkwhale/custom">
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
Once done, reload your reverse proxy, refresh Funkwhale in your web browser, and you should see a red background.
Note
You can reference external urls as well in additionalStylesheets
, simply use
the full urls. Be especially careful with external urls as they may affect your users
privacy.
Warning
Loading additional stylesheets and CSS rules can affect the performance and usability of your instance. If you encounter issues with the interfaces and use custom stylesheets, try to disable those to ensure the issue is not caused by your customizations.