Finished Funkwhale implementation

This commit is contained in:
Kevin Veen-Birkenbach 2025-07-02 02:07:41 +02:00
parent 28b41382d2
commit 2ccfdf0de6
No known key found for this signature in database
GPG Key ID: 44D8F11FD62F878E
10 changed files with 140 additions and 48 deletions

View File

@ -62,7 +62,7 @@ ldap:
surname: "sn" surname: "sn"
ssh_public_key: "sshPublicKey" ssh_public_key: "sshPublicKey"
# Password to access dn.bind # Password to access dn.bind
bind_credential: "{{applications.ldap.credentials.administrator_database_password}}" bind_credential: "{{ applications.ldap.credentials.administrator_database_password }}"
server: server:
domain: "{{applications.ldap.hostname if applications.ldap.network.docker | bool else domains.ldap}}" # Mapping for public or locale access domain: "{{applications.ldap.hostname if applications.ldap.network.docker | bool else domains.ldap}}" # Mapping for public or locale access
port: "{{_ldap_server_port}}" port: "{{_ldap_server_port}}"

View File

@ -5,3 +5,60 @@
```bash ```bash
docker-compose down && docker volume rm funkwhale_data docker-compose down && docker volume rm funkwhale_data
``` ```
## create admin account
```bash
docker compose exec -T api funkwhale-manage fw users create --superuser
```
## ldap debugging
```bash
docker compose exec -T api funkwhale-manage shell
import logging
logging.basicConfig(level=logging.DEBUG)
from django.contrib.auth import authenticate
user = authenticate(username="kevinveenbirkenbach", password="DEINPASSWORT")
print(user)
#######
from django_auth_ldap.backend import LDAPBackend
from django_auth_ldap.config import LDAPSearch
from ldap import initialize
# Zugriff auf deine Funkwhale-Einstellungen
import django.conf
settings = django.conf.settings
# Verbindung aufbauen
conn = initialize(settings.AUTH_LDAP_SERVER_URI)
conn.simple_bind_s(settings.AUTH_LDAP_BIND_DN, settings.AUTH_LDAP_BIND_PASSWORD)
# Benutzername einsetzen
username = "kevinveenbirkenbach"
# Search-Filter einsetzen
search_filter = settings.AUTH_LDAP_USER_SEARCH.search_filter.format(username)
base_dn = settings.AUTH_LDAP_USER_SEARCH.base_dn
scope = settings.AUTH_LDAP_USER_SEARCH.scope
# Suche durchführen
results = conn.search_s(base_dn, scope, search_filter)
print(results)
##########
from django.conf import settings
print("LDAP Server URI:", settings.AUTH_LDAP_SERVER_URI)
print("Bind DN:", settings.AUTH_LDAP_BIND_DN)
print("Bind Password:", settings.AUTH_LDAP_BIND_PASSWORD)
print("Search Base:", settings.AUTH_LDAP_USER_SEARCH.base_dn)
print("Search Filter:", settings.AUTH_LDAP_USER_SEARCH.search_filter)
print("User Attr Map:", settings.AUTH_LDAP_USER_ATTR_MAP)
```

View File

@ -18,4 +18,5 @@ galaxy_info:
documentation: https://s.veen.world/cymais documentation: https://s.veen.world/cymais
logo: logo:
class: "fa-solid fa-music" class: "fa-solid fa-music"
dependencies: [] run_after:
- docker-ldap

View File

@ -1,5 +1,4 @@
services: services:
# @todo Test which containers can be removed crom cental_database networks
{% include 'roles/docker-central-database/templates/services/' + database_type + '.yml.j2' %} {% include 'roles/docker-central-database/templates/services/' + database_type + '.yml.j2' %}
{% include 'templates/docker/services/redis.yml.j2' %} {% include 'templates/docker/services/redis.yml.j2' %}
@ -14,53 +13,51 @@ services:
# flag: # flag:
# celery -A funkwhale_api.taskapp worker -l INFO --concurrency=4 # celery -A funkwhale_api.taskapp worker -l INFO --concurrency=4
{% include 'roles/docker-compose/templates/services/base.yml.j2' %} {% include 'roles/docker-compose/templates/services/base.yml.j2' %}
image: "{{ applications[application_id].images.api }}" image: "{{ applications | get_docker_image(application_id,'api') }}"
command: celery -A funkwhale_api.taskapp worker -l INFO --concurrency={{celeryd_concurrency}} command: celery -A funkwhale_api.taskapp worker -l INFO --concurrency={{celeryd_concurrency}}
environment: environment:
- C_FORCE_ROOT=true - C_FORCE_ROOT=true
volumes: volumes:
- "data:{{media_root}}" - "data:{{funkwhale_media_root}}"
- "music:{{music_directory_path}}:ro" - "music:{{funkwhale_music_directory_path}}:ro"
{% include 'templates/docker/container/depends-on-database-redis.yml.j2' %} {% include 'templates/docker/container/depends-on-database-redis.yml.j2' %}
{% include 'templates/docker/container/networks.yml.j2' %} {% include 'templates/docker/container/networks.yml.j2' %}
celerybeat: celerybeat:
{% include 'roles/docker-compose/templates/services/base.yml.j2' %} {% include 'roles/docker-compose/templates/services/base.yml.j2' %}
image: "{{ applications[application_id].images.api }}" image: "{{ applications | get_docker_image(application_id,'api') }}"
command: celery -A funkwhale_api.taskapp beat --pidfile= -l INFO command: celery -A funkwhale_api.taskapp beat --pidfile= -l INFO
{% include 'templates/docker/container/depends-on-database-redis.yml.j2' %} {% include 'templates/docker/container/depends-on-database-redis.yml.j2' %}
{% include 'templates/docker/container/networks.yml.j2' %} {% include 'templates/docker/container/networks.yml.j2' %}
api: api:
{% include 'roles/docker-compose/templates/services/base.yml.j2' %} {% include 'roles/docker-compose/templates/services/base.yml.j2' %}
image: "{{ applications[application_id].images.api }}" image: "{{ applications | get_docker_image(application_id,'api') }}"
volumes: volumes:
- "music:{{music_directory_path}}:ro" - "music:{{funkwhale_music_directory_path}}:ro"
- "data:{{media_root}}" - "data:{{funkwhale_media_root}}"
- "static_root:{{static_root}}" - "funkwhale_static_root:{{funkwhale_static_root}}"
ports: ports:
- "5000" # Exposes API just in local docker network to be used by front container - "{{ funkwhale_docker_api_port }}"
{% include 'templates/docker/container/depends-on-database-redis.yml.j2' %} {% include 'templates/docker/container/depends-on-database-redis.yml.j2' %}
{% include 'templates/docker/container/networks.yml.j2' %} {% include 'templates/docker/container/networks.yml.j2' %}
front: front:
{% include 'roles/docker-compose/templates/services/base.yml.j2' %} {% include 'roles/docker-compose/templates/services/base.yml.j2' %}
image: "{{ applications[application_id].images.front }}" image: "{{ applications | get_docker_image(application_id,'front') }}"
depends_on: depends_on:
- api - api
environment: environment:
# Override those variables in your .env file if needed
- "NGINX_MAX_BODY_SIZE=100M" - "NGINX_MAX_BODY_SIZE=100M"
volumes: volumes:
- "data:{{media_root}}:ro" - "data:{{funkwhale_media_root}}:ro"
#- "{{static_root}}:{{static_root}}:ro" #- "{{funkwhale_static_root}}:{{funkwhale_static_root}}:ro"
ports: ports:
# override those variables in your .env file if needed
- "127.0.0.1:{{ports.localhost.http[application_id]}}:80" - "127.0.0.1:{{ports.localhost.http[application_id]}}:80"
typesense: typesense:
{% include 'roles/docker-compose/templates/services/base.yml.j2' %} {% include 'roles/docker-compose/templates/services/base.yml.j2' %}
image: "{{ applications[application_id].images.typesense }}" image: "{{ applications[application_id].docker.images.typesense }}"
volumes: volumes:
- ./typesense/data:/data - ./typesense/data:/data
command: --data-dir /data --enable-cors command: --data-dir /data --enable-cors
@ -69,7 +66,7 @@ services:
{% include 'templates/docker/compose/volumes.yml.j2' %} {% include 'templates/docker/compose/volumes.yml.j2' %}
data: data:
static_root: funkwhale_static_root:
redis: redis:
music: music:

View File

@ -17,11 +17,7 @@
# #
# Docker only # Docker only
# ----------- # -----------
MUSIC_DIRECTORY_PATH={{music_directory_path}} MUSIC_DIRECTORY_PATH={{funkwhale_music_directory_path}}
# Assuming that the following variable isn't used anymore.
# @todo remove it if this is true
FUNKWHALE_VERSION={{applications.funkwhale.version}}
# End of docker-only configuration # End of docker-only configuration
@ -32,7 +28,7 @@ FUNKWHALE_VERSION={{applications.funkwhale.version}}
FUNKWHALE_API_IP=127.0.0.1 FUNKWHALE_API_IP=127.0.0.1
# Assuming that the following variable isn't used anymore. # Assuming that the following variable isn't used anymore.
# @todo remove it if this is true # @todo remove it if this is true
FUNKWHALE_API_PORT={{ports.localhost.http[application_id]}}: FUNKWHALE_API_PORT={{ funkwhale_docker_api_port }}
# The number of web workers to start in parallel. Higher means you can handle # The number of web workers to start in parallel. Higher means you can handle
# more concurrent requests, but also leads to higher CPU/Memory usage # more concurrent requests, but also leads to higher CPU/Memory usage
@ -46,6 +42,9 @@ FUNKWHALE_PROTOCOL={{ web_protocol }}
# Log level (debug, info, warning, error, critical) # Log level (debug, info, warning, error, critical)
LOGLEVEL={% if enable_debug | bool %}debug{% else %}error{% endif %} LOGLEVEL={% if enable_debug | bool %}debug{% else %}error{% endif %}
# Could be that this is redundant
DJANGO_LOGLEVEL={% if enable_debug | bool %}debug{% else %}error{% endif %}
# Configure e-mail sending using this variale # Configure e-mail sending using this variale
# By default, funkwhale will output e-mails sent to stdout # By default, funkwhale will output e-mails sent to stdout
# here are a few examples for this setting # here are a few examples for this setting
@ -86,12 +85,12 @@ CELERYD_CONCURRENCY={{celeryd_concurrency}}
# Where media files (such as album covers or audio tracks) should be stored # Where media files (such as album covers or audio tracks) should be stored
# on your system? # on your system?
# (Ensure this directory actually exists) # (Ensure this directory actually exists)
MEDIA_ROOT={{media_root}} MEDIA_ROOT={{funkwhale_media_root}}
# Where static files (such as API css or icons) should be compiled # Where static files (such as API css or icons) should be compiled
# on your system? # on your system?
# (Ensure this directory actually exists) # (Ensure this directory actually exists)
STATIC_ROOT={{static_root}} STATIC_ROOT={{funkwhale_static_root}}
# which settings module should django use? # which settings module should django use?
# You don't have to touch this unless you really know what you're doing # You don't have to touch this unless you really know what you're doing
@ -106,14 +105,17 @@ DJANGO_SECRET_KEY={{applications[application_id].credentials.django_secret}}
# using a LDAP directory. # using a LDAP directory.
# Have a look at https://docs.funkwhale.audio/installation/ldap.html for # Have a look at https://docs.funkwhale.audio/installation/ldap.html for
# detailed instructions. # detailed instructions.
# Commit: https://gitea.fudaoyuan.icu/Github/funkwhale/commit/4ce46ff2a000646a3dbab80f0ca9fd8d7f8ae24c
LDAP_ENABLED = True
LDAP_SERVER_URI = "{{ ldap.server.uri }}"
LDAP_BIND_DN = "{{ ldap.dn.administrator.data }}"
LDAP_BIND_PASSWORD = "{{ ldap.bind_credential }}"
#LDAP_SEARCH_FILTER = "{{ ldap.filters.users.login | replace('%' ~ ldap.attributes.user_id, '{0}') }}"
LDAP_START_TLS = False
LDAP_ROOT_DN = "{{ldap.dn.root}}"
#LDAP_USER_ATTR_MAP = "first_name:{{ ldap.attributes.firstname }}, last_name:{{ ldap.attributes.surname }}, username:{{ ldap.attributes.user_id }}, email:{{ ldap.attributes.mail }}"
LDAP_ENABLED = True
LDAP_SERVER_URI = "{{ldap.server.uri}}"
LDAP_BIND_DN = "{{ldap.dn.administrator.data}}"
LDAP_BIND_PASSWORD = "{{ldap.bind_credential}}"
LDAP_SEARCH_FILTER = "(|(cn={0})(mail={0}))"
LDAP_START_TLS = False
LDAP_ROOT_DN = "{{ldap.dn.root}}"
{% endif %} {% endif %}
FUNKWHALE_FRONTEND_PATH=/srv/funkwhale/front/dist FUNKWHALE_FRONTEND_PATH=/srv/funkwhale/front/dist

View File

@ -1,13 +1,19 @@
images: docker:
api: "funkwhale/api:1.4.0" versions:
front: "funkwhale/front:1.4.0" api: "1.4.0"
typesense: "typesense/typesense" front: "1.4.0"
typesense: "typesense/typesense"
images:
api: "funkwhale/api"
front: "funkwhale/front"
typesense: "typesense/typesense"
features: features:
matomo: true matomo: true
css: true css: false
portfolio_iframe: true portfolio_iframe: true
ldap: true ldap: true
central_database: true central_database: true
oauth2: false # Doesn't make sense to activate it atm, because login is possible on homepage
credentials: credentials:
domains: domains:
canonical: canonical:
@ -15,3 +21,16 @@ domains:
aliases: aliases:
- "music.{{ primary_domain }}" - "music.{{ primary_domain }}"
- "sound.{{ primary_domain }}" - "sound.{{ primary_domain }}"
csp:
flags:
style-src:
unsafe-inline: true
whitelist:
font-src:
- "data:"
oauth2_proxy:
application: "front"
port: "80"
acl:
blacklist:
- "/login"

View File

@ -1,7 +1,8 @@
application_id: "funkwhale" application_id: "funkwhale"
nginx_docker_reverse_proxy_extra_configuration: "client_max_body_size 512M;" nginx_docker_reverse_proxy_extra_configuration: "client_max_body_size 512M;"
database_type: "postgres" database_type: "postgres"
media_root: "/srv/funkwhale/data/" funkwhale_media_root: "/srv/funkwhale/data/"
static_root: "{{media_root}}static" funkwhale_static_root: "{{funkwhale_media_root}}static"
celeryd_concurrency: 1 celeryd_concurrency: 1
music_directory_path: "/music" funkwhale_music_directory_path: "/music"
funkwhale_docker_api_port: 5000

View File

@ -2,16 +2,16 @@
# @See https://hub.docker.com/r/bitnami/openldap # @See https://hub.docker.com/r/bitnami/openldap
# GENERAL # GENERAL
## Database ## Admin (Data)
LDAP_ADMIN_USERNAME= {{applications[application_id].users.administrator.username}} # LDAP database admin user. LDAP_ADMIN_USERNAME= {{applications[application_id].users.administrator.username}} # LDAP database admin user.
LDAP_ADMIN_PASSWORD= {{applications[application_id].credentials.administrator_database_password}} # LDAP database admin password. LDAP_ADMIN_PASSWORD= {{ldap.bind_credential}} # LDAP database admin password.
## Users ## Users
LDAP_USERS= ' ' # Comma separated list of LDAP users to create in the default LDAP tree. Default: user01,user02 LDAP_USERS= ' ' # Comma separated list of LDAP users to create in the default LDAP tree. Default: user01,user02
LDAP_PASSWORDS= ' ' # Comma separated list of passwords to use for LDAP users. Default: bitnami1,bitnami2 LDAP_PASSWORDS= ' ' # Comma separated list of passwords to use for LDAP users. Default: bitnami1,bitnami2
LDAP_ROOT= {{ldap.dn.root}} # LDAP baseDN (or suffix) of the LDAP tree. Default: dc=example,dc=org LDAP_ROOT= {{ldap.dn.root}} # LDAP baseDN (or suffix) of the LDAP tree. Default: dc=example,dc=org
## Admin ## Admin (Config)
LDAP_ADMIN_DN= {{ldap.dn.administrator.data}} LDAP_ADMIN_DN= {{ldap.dn.administrator.data}}
LDAP_CONFIG_ADMIN_ENABLED= yes LDAP_CONFIG_ADMIN_ENABLED= yes
LDAP_CONFIG_ADMIN_USERNAME= {{applications[application_id].users.administrator.username}} LDAP_CONFIG_ADMIN_USERNAME= {{applications[application_id].users.administrator.username}}

View File

@ -33,3 +33,17 @@
token_auth: "{{ matomo_auth_token }}" token_auth: "{{ matomo_auth_token }}"
return_content: yes return_content: yes
status_code: 200 status_code: 200
- name: Exclude CSP-CheckerBot user agent in Matomo
uri:
url: "{{ matomo_index_php_url }}"
method: POST
body_format: form-urlencoded
body:
module: API
method: SitesManager.setGlobalExcludedUserAgents
excludedUserAgents: "CSP-CheckerBot"
format: json
token_auth: "{{ matomo_auth_token }}"
return_content: yes
status_code: 200

View File

@ -4,6 +4,7 @@ images:
features: features:
central_database: true central_database: true
oidc: true oidc: true
matomo: true
csp: csp:
flags: flags:
script-src-elem: script-src-elem: