feat(compose): complete development setup documentation

This commit is contained in:
jon r 2024-10-02 16:05:28 +02:00
parent b584de1ea3
commit f21795ede3
32 changed files with 280 additions and 590 deletions

View File

@ -1,11 +1,18 @@
# api + celeryworker
DEBUG=True
FUNKWHALE_DOMAIN=funkwhale.test
FUNKWHALE_PROTOCOL=https
DJANGO_SECRET_KEY=dev
DJANGO_ALLOWED_HOSTS=.funkwhale.test,nginx
DJANGO_SETTINGS_MODULE=config.settings.local
DATABASE_URL=postgresql://postgres@postgres/postgres
CACHE_URL=redis://redis:6379/0
DJANGO_SECRET_KEY=dev
FORCE_HTTPS_URLS=True
EXTERNAL_REQUESTS_VERIFY_SSL=false
C_FORCE_ROOT=true
PYTHONDONTWRITEBYTECODE=true

View File

@ -1,9 +0,0 @@
# api + celeryworker
DJANGO_ALLOWED_HOSTS=.funkwhale.test,nginx
DJANGO_SETTINGS_MODULE=config.settings.local
FUNKWHALE_DOMAIN=funkwhale.test
FUNKWHALE_PROTOCOL=https
FORCE_HTTPS_URLS=True
EXTERNAL_REQUESTS_VERIFY_SSL=false

View File

@ -1,12 +0,0 @@
# api + celeryworker
DJANGO_ALLOWED_HOSTS=localhost,nginx,0.0.0.0,127.0.0.1
DJANGO_SETTINGS_MODULE=config.settings.local
FUNKWHALE_PROTOCOL=http
FUNKWHALE_HOSTNAME=localhost
FUNKWHALE_PORT=8000
FUNKWHALE_URL=${FUNKWHALE_PROTOCOL}://${FUNKWHALE_HOSTNAME}:${FUNKWHALE_PORT}
MEDIA_URL=${FUNKWHALE_URL}/media/
STATIC_URL=${FUNKWHALE_URL}/staticfiles/

2
.gitignore vendored
View File

@ -93,6 +93,7 @@ docs/_build
front/tauri/gen
/data/
.state
.env
po/*.po
@ -103,6 +104,7 @@ _build
# Docker
docker-bake.*.json
metadata.json
compose/var/test.*
# Linting
.eslintcache

View File

@ -224,23 +224,9 @@ ALLOWED_HOSTS = env.list("DJANGO_ALLOWED_HOSTS", default=[]) + [FUNKWHALE_HOSTNA
List of allowed hostnames for which the Funkwhale server will answer.
"""
try:
FUNKWHALE_PORT = env.int("FUNKWHALE_PORT")
except Exception as e:
logger.warning(f"Funkwhale is served from default port. {e}")
try:
CSRF_TRUSTED_ORIGINS = [
urlparse(
"//" + o + (":" + str(FUNKWHALE_PORT) if (FUNKWHALE_PORT != 80) else ""),
FUNKWHALE_PROTOCOL,
).geturl()
for o in ALLOWED_HOSTS
]
except Exception:
CSRF_TRUSTED_ORIGINS = [
urlparse("//" + o, FUNKWHALE_PROTOCOL).geturl() for o in ALLOWED_HOSTS
]
CSRF_TRUSTED_ORIGINS = [
urlparse("//" + o, FUNKWHALE_PROTOCOL).geturl() for o in ALLOWED_HOSTS
]
"""
List of origins that are trusted for unsafe requests
We simply consider all allowed hosts to be trusted origins

View File

@ -1,8 +0,0 @@
include:
- path: docker/app.default.yml
env_file:
- .env.default
- path: docker/env.local.yml
env_file:
- .env.local
- .env.default

View File

@ -1,7 +1,9 @@
name: funkwhale-services
include:
- path: docker/net.dnsmasq.yml
- path: docker/net.traefik.yml
# uncomment on Linux hosts with empty docker0 bridges, which else are DOWN
# - path: docker/net.helpers.resolved.yml
- path: docker/net.verify.yml
- path: compose/net.dnsmasq.yml
- path: compose/net.traefik.yml
# Uncomment this line if your docker0 network does not stay up, because it
# is empty and has no containers attached to it.
#
- path: compose/net.helpers.docker0.yml
- path: compose/net.verify.yml

View File

@ -1,8 +1,137 @@
include:
- path: docker/app.default.yml
env_file:
- .env.default
- path: docker/env.federation.yml
env_file:
- .env.federation
- .env.default
networks:
internal:
federation:
external: true
x-django: &django
environment:
- DEBUG
- DJANGO_SETTINGS_MODULE
- DJANGO_SECRET_KEY
- EXTERNAL_REQUESTS_VERIFY_SSL
- "FORCE_HTTPS_URLS=${FORCE_HTTPS_URLS:-False}"
- FUNKWHALE_PROTOCOL
- "FUNKWHALE_HOSTNAME=${COMPOSE_PROJECT_NAME:-funkwhale}.${FUNKWHALE_DOMAIN}"
- DATABASE_URL
- CACHE_URL
- "STATIC_URL=${FUNKWHALE_PROTOCOL}://${COMPOSE_PROJECT_NAME:-funkwhale}.${FUNKWHALE_DOMAIN}/static/"
- "MEDIA_URL=${FUNKWHALE_PROTOCOL}://${COMPOSE_PROJECT_NAME:-funkwhale}.${FUNKWHALE_DOMAIN}/media/"
- STATIC_ROOT
- MEDIA_ROOT
- FUNKWHALE_SPA_HTML_ROOT
- LDAP_ENABLED
- BROWSABLE_API_ENABLED
- "MUSIC_DIRECTORY_PATH=${MUSIC_DIRECTORY_PATH:-/music}"
- C_FORCE_ROOT
- PYTHONDONTWRITEBYTECODE
- PYTHONTRACEMALLOC
dns: 172.17.0.1
dns_search: funkwhale.test
services:
front:
build:
context: ../front
dockerfile: Dockerfile.dev
ports:
- "${VUE_PORT:-8080}:${VUE_PORT:-8080}"
environment:
- HOST
- VUE_PORT
volumes:
- "./front:/app"
- "/app/node_modules"
- "./po:/po"
networks:
- internal
command: "yarn dev --host"
api:
extends:
file: ./compose/app.django.yml
service: api
<<: *django
celeryworker:
extends:
file: ./compose/app.django.yml
service: celeryworker
<<: *django
migrate:
extends:
file: ./compose/app.django.yml
service: migrate
<<: *django
nginx:
extends:
file: ./compose/app.nginx.yml
service: nginx
environment:
- "MUSIC_DIRECTORY_PATH=${MUSIC_DIRECTORY_PATH:-/music}"
- "FUNKWHALE_HOSTNAME=${COMPOSE_PROJECT_NAME:-funkwhale}.${FUNKWHALE_DOMAIN}"
- FUNKWHALE_PROTOCOL
- FUNKWHALE_API_HOST
- FUNKWHALE_API_PORT
- FUNKWHALE_FRONT_IP
- FUNKWHALE_FRONT_PORT
- NGINX_MAX_BODY_SIZE
- STATIC_ROOT
- "MEDIA_ROOT=${MEDIA_ROOT:-/data/media}"
networks:
- federation
- internal
labels:
- "traefik.enable=true"
- "traefik.http.routers.funkwhale-${COMPOSE_PROJECT_NAME:-funkwhale}-web.rule=Host(`${COMPOSE_PROJECT_NAME:-funkwhale}.${FUNKWHALE_DOMAIN}`)"
- "traefik.http.routers.funkwhale-${COMPOSE_PROJECT_NAME:-funkwhale}-web.entrypoints=web"
- "traefik.http.routers.funkwhale-${COMPOSE_PROJECT_NAME:-funkwhale}-webs.rule=Host(`${COMPOSE_PROJECT_NAME:-funkwhale}.${FUNKWHALE_DOMAIN}`)"
- "traefik.http.routers.funkwhale-${COMPOSE_PROJECT_NAME:-funkwhale}-webs.entrypoints=webs"
- "traefik.http.routers.funkwhale-${COMPOSE_PROJECT_NAME:-funkwhale}-webs.tls=true"
- "traefik.http.routers.funkwhale-${COMPOSE_PROJECT_NAME:-funkwhale}-webs.tls.domains[0].main=${COMPOSE_PROJECT_NAME:-funkwhale}.${FUNKWHALE_DOMAIN}"
postgres:
image: "postgres:${POSTGRES_VERSION:-15}-alpine"
environment:
- POSTGRES_HOST_AUTH_METHOD
command: postgres ${POSTGRES_ARGS:-}
volumes:
- "./.state/${COMPOSE_PROJECT_NAME:-funkwhale}/postgres:/var/lib/postgresql/data"
networks:
- internal
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
volumes:
- "./.state/${COMPOSE_PROJECT_NAME:-funkwhale}/redis:/data"
networks:
- internal
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3

View File

@ -2,11 +2,11 @@ x-django: &django
image: funkwhale-api
volumes:
- ../api:/app
- "${MUSIC_DIRECTORY_SERVE_PATH-../data/music}:/music:ro"
- "../data/plugins:/srv/funkwhale/plugins"
- "../data/staticfiles:/staticfiles"
- "../data/media:/protected/media"
- "../data/${COMPOSE_PROJECT_NAME}/media:/data/media"
- "${MUSIC_DIRECTORY_SERVE_PATH-../.state/music}:/music:ro"
- "../.state/plugins:/srv/funkwhale/plugins"
- "../.state/staticfiles:/staticfiles"
- "../.state/media:/protected/media"
- "../.state/${COMPOSE_PROJECT_NAME:-funkwhale}/media:/data/media"
depends_on:
postgres:
condition: service_healthy

View File

@ -5,14 +5,14 @@ services:
- api
- front
volumes:
- "${MUSIC_DIRECTORY_SERVE_PATH:-../data/music}:${MUSIC_DIRECTORY_PATH:-/music}:ro"
- "${MUSIC_DIRECTORY_SERVE_PATH:-../.state/music}:${MUSIC_DIRECTORY_PATH:-/music}:ro"
- ./etc/nginx/conf.dev:/etc/nginx/templates/default.conf.template:ro
- ../deploy/funkwhale_proxy.conf:/etc/nginx/funkwhale_proxy.conf:ro
- ../front:/frontend:ro
- ../data/staticfiles:/usr/share/nginx/html/staticfiles:ro
- ../data/media:/protected/media:ro
- ../data/${COMPOSE_PROJECT_NAME}/media:/data/media:ro
- ../.state/staticfiles:/usr/share/nginx/html/staticfiles:ro
- ../.state/media:/protected/media:ro
- ../.state/${COMPOSE_PROJECT_NAME:-funkwhale}/media:/data/media:ro
networks:
- internal

View File

@ -0,0 +1,3 @@
FROM mwalbeck/python-poetry
RUN apt update && \
apt install -y make

View File

@ -161,7 +161,7 @@ server {
return 302 ${FUNKWHALE_PROTOCOL}://${FUNKWHALE_HOSTNAME}/api/v1/instance/spa-manifest.json;
}
location /staticfiles/ {
location /static/ {
alias /usr/share/nginx/html/staticfiles/;
}
}

View File

@ -0,0 +1,4 @@
tls:
certificates:
- certFile: /ssl/test.crt
keyFile: /ssl/test.key

View File

@ -1,15 +1,16 @@
providers:
docker:
exposedByDefault: "false"
exposedByDefault: false
file:
directory: /etc/traefik/dynamic
watch: true
log:
level: debug
api:
insecure: true
tls:
certificates:
- certFile: /ssl/traefik.crt
keyFile: /ssl/traefik.key
entryPoints:
traefik:
address: "172.17.0.1:8008"

View File

@ -3,7 +3,7 @@ services:
image: minio/minio
command: server /data
volumes:
- "./data/${COMPOSE_PROJECT_NAME:-node1}/minio:/data"
- "../.state/${COMPOSE_PROJECT_NAME:-funkwhale}/minio:/data"
environment:
- "MINIO_ACCESS_KEY=${AWS_ACCESS_KEY_ID-access_key}"
- "MINIO_SECRET_KEY=${AWS_SECRET_ACCESS_KEY-secret_key}"

View File

@ -4,6 +4,7 @@ services:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./etc/traefik/traefik.yml:/etc/traefik/traefik.yml
- ./var/test.key:/ssl/traefik.key
- ./var/test.crt:/ssl/traefik.crt
- ./etc/traefik/dynamic:/etc/traefik/dynamic
- ./var/test.key:/ssl/test.key
- ./var/test.crt:/ssl/test.crt
network_mode: host

View File

@ -12,4 +12,4 @@ services:
verify-internal-connectivity:
<<: *verify
command: "ping -c 1 ${COMPOSE_PROJECT_NAME}.funkwhale.test"
command: "ping -c 1 ${COMPOSE_PROJECT_NAME:-funkwhale}.funkwhale.test"

0
compose/var/.keep Normal file
View File

View File

@ -1,49 +0,0 @@
networks:
internal:
federation:
external: true
services:
front:
build:
context: ../front
dockerfile: Dockerfile.dev
ports:
- "${VUE_PORT:-8080}:${VUE_PORT:-8080}"
environment:
- HOST
- VUE_PORT
volumes:
- "../front:/app"
- "/app/node_modules"
- "../po:/po"
networks:
- internal
command: "yarn dev --host"
postgres:
image: "postgres:${POSTGRES_VERSION:-15}-alpine"
environment:
- POSTGRES_HOST_AUTH_METHOD
command: postgres ${POSTGRES_ARGS:-}
volumes:
- "../data/${COMPOSE_PROJECT_NAME:-funkwhale}/postgres:/var/lib/postgresql/data"
networks:
- internal
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
volumes:
- "../data/${COMPOSE_PROJECT_NAME:-funkwhale}/redis:/data"
networks:
- internal
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3

View File

@ -1,93 +0,0 @@
networks:
internal:
federation:
external: true
x-federation: &federation
environment:
- DEBUG
- DJANGO_SETTINGS_MODULE
- DJANGO_SECRET_KEY
- EXTERNAL_REQUESTS_VERIFY_SSL
- "FORCE_HTTPS_URLS=${FORCE_HTTPS_URLS:-False}"
- FUNKWHALE_PROTOCOL
- "FUNKWHALE_HOSTNAME=${COMPOSE_PROJECT_NAME:-funkwhale}.${FUNKWHALE_DOMAIN}"
- DATABASE_URL
- CACHE_URL
- "STATIC_URL=${FUNKWHALE_PROTOCOL}://${COMPOSE_PROJECT_NAME:-funkwhale}.${FUNKWHALE_DOMAIN}/static/"
- "MEDIA_URL=${FUNKWHALE_PROTOCOL}://${COMPOSE_PROJECT_NAME:-funkwhale}.${FUNKWHALE_DOMAIN}/media/"
- STATIC_ROOT
- MEDIA_ROOT
- FUNKWHALE_SPA_HTML_ROOT
- LDAP_ENABLED
- BROWSABLE_API_ENABLED
- "MUSIC_DIRECTORY_PATH=${MUSIC_DIRECTORY_PATH:-/music}"
- C_FORCE_ROOT
- PYTHONDONTWRITEBYTECODE
- PYTHONTRACEMALLOC
dns: 172.17.0.1
dns_search: funkwhale.test
services:
api:
extends:
file: ./app.django.yml
service: api
<<: *federation
celeryworker:
extends:
file: ./app.django.yml
service: celeryworker
<<: *federation
migrate:
extends:
file: ./app.django.yml
service: migrate
<<: *federation
nginx:
extends:
file: ./app.nginx.yml
service: nginx
environment:
- "MUSIC_DIRECTORY_PATH=${MUSIC_DIRECTORY_PATH:-/music}"
- "FUNKWHALE_HOSTNAME=${COMPOSE_PROJECT_NAME:-funkwhale}.${FUNKWHALE_DOMAIN}"
- FUNKWHALE_PROTOCOL
- FUNKWHALE_API_HOST
- FUNKWHALE_API_PORT
- FUNKWHALE_FRONT_IP
- FUNKWHALE_FRONT_PORT
- NGINX_MAX_BODY_SIZE
- STATIC_ROOT
- "MEDIA_ROOT=${MEDIA_ROOT:-/data/media}"
networks:
- federation
- internal
labels:
- "traefik.enable=true"
- "traefik.http.routers.funkwhale-${COMPOSE_PROJECT_NAME:-funkwhale}-web.rule=Host(`${COMPOSE_PROJECT_NAME:-funkwhale}.${FUNKWHALE_DOMAIN}`)"
- "traefik.http.routers.funkwhale-${COMPOSE_PROJECT_NAME:-funkwhale}-web.entrypoints=web"
- "traefik.http.routers.funkwhale-${COMPOSE_PROJECT_NAME:-funkwhale}-webs.rule=Host(`${COMPOSE_PROJECT_NAME:-funkwhale}.${FUNKWHALE_DOMAIN}`)"
- "traefik.http.routers.funkwhale-${COMPOSE_PROJECT_NAME:-funkwhale}-webs.entrypoints=webs"
- "traefik.http.routers.funkwhale-${COMPOSE_PROJECT_NAME:-funkwhale}-webs.tls=true"
- "traefik.http.routers.funkwhale-${COMPOSE_PROJECT_NAME:-funkwhale}-webs.tls.domains[0].main=${COMPOSE_PROJECT_NAME:-funkwhale}.${FUNKWHALE_DOMAIN}"

View File

@ -1,76 +0,0 @@
networks:
internal:
x-local: &local
environment:
- DEBUG
- DJANGO_SETTINGS_MODULE
- DJANGO_SECRET_KEY
- "FORCE_HTTPS_URLS=${FORCE_HTTPS_URLS:-False}"
- FUNKWHALE_PROTOCOL
- FUNKWHALE_HOSTNAME
- FUNKWHALE_PORT
- DATABASE_URL
- CACHE_URL
- STATIC_URL
- MEDIA_URL
- STATIC_ROOT
- MEDIA_ROOT
- FUNKWHALE_SPA_HTML_ROOT
- LDAP_ENABLED
- BROWSABLE_API_ENABLED
- "MUSIC_DIRECTORY_PATH=${MUSIC_DIRECTORY_PATH:-/music}"
- C_FORCE_ROOT
- PYTHONDONTWRITEBYTECODE
- PYTHONTRACEMALLOC
services:
api:
extends:
file: ./app.django.yml
service: api
<<: *local
celeryworker:
extends:
file: ./app.django.yml
service: celeryworker
<<: *local
migrate:
extends:
file: ./app.django.yml
service: migrate
<<: *local
nginx:
extends:
file: ./app.nginx.yml
service: nginx
ports:
- "${NGINX_HOST_PORT:-8000:80}"
environment:
- "MUSIC_DIRECTORY_PATH=${MUSIC_DIRECTORY_PATH:-/music}"
- "FUNKWHALE_HOSTNAME=${FUNKWHALE_HOSTNAME:-localhost}"
- FUNKWHALE_PROTOCOL
- FUNKWHALE_API_HOST
- FUNKWHALE_API_PORT
- FUNKWHALE_FRONT_IP
- FUNKWHALE_FRONT_PORT
- NGINX_MAX_BODY_SIZE
- STATIC_ROOT
- "MEDIA_ROOT=${MEDIA_ROOT:-/data/media}"
networks:
- internal

View File

@ -1,88 +0,0 @@
# cf https://stackoverflow.com/questions/10175812/how-to-create-a-self-signed-certificate-with-openssl/27931596#27931596
# create with openssl req -config openssl.conf -new -x509 -sha256 -newkey rsa:2048 -nodes -keyout test.key -days 365 -out test.crt
[ req ]
default_bits = 2048
default_keyfile = server-key.pem
distinguished_name = subject
req_extensions = req_ext
x509_extensions = x509_ext
string_mask = utf8only
# The Subject DN can be formed using X501 or RFC 4514 (see RFC 4519 for a description).
# Its sort of a mashup. For example, RFC 4514 does not provide emailAddress.
[ subject ]
countryName = Country Name (2 letter code)
countryName_default = US
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = NY
localityName = Locality Name (eg, city)
localityName_default = New York
organizationName = Organization Name (eg, company)
organizationName_default = Example, LLC
# Use a friendly name here because it's presented to the user. The server's DNS
# names are placed in Subject Alternate Names. Plus, DNS names here is deprecated
# by both IETF and CA/Browser Forums. If you place a DNS name here, then you
# must include the DNS name in the SAN too (otherwise, Chrome and others that
# strictly follow the CA/Browser Baseline Requirements will fail).
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_default = Example Company
emailAddress = Email Address
emailAddress_default = test@example.com
# Section x509_ext is used when generating a self-signed certificate. I.e., openssl req -x509 ...
[ x509_ext ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
# You only need digitalSignature below. *If* you don't allow
# RSA Key transport (i.e., you use ephemeral cipher suites), then
# omit keyEncipherment because that's key transport.
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alternate_names
nsComment = "OpenSSL Generated Certificate"
# RFC 5280, Section 4.2.1.12 makes EKU optional
# CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused
# In either case, you probably only need serverAuth.
# extendedKeyUsage = serverAuth, clientAuth
# Section req_ext is used when generating a certificate signing request. I.e., openssl req ...
[ req_ext ]
subjectKeyIdentifier = hash
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alternate_names
nsComment = "OpenSSL Generated Certificate"
# RFC 5280, Section 4.2.1.12 makes EKU optional
# CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused
# In either case, you probably only need serverAuth.
# extendedKeyUsage = serverAuth, clientAuth
[ alternate_names ]
DNS.1 = funkwhale.test
DNS.2 = node1.funkwhale.test
DNS.3 = node2.funkwhale.test
DNS.4 = node3.funkwhale.test
DNS.5 = localhost
DNS.6 = 127.0.0.1
# Add these if you need them. But usually you don't want them or
# need them in production. You may need them for development.
# DNS.5 = localhost
# DNS.6 = localhost.localdomain
# DNS.7 = 127.0.0.1
# IPv6 localhost
# DNS.8 = ::1

View File

@ -1,27 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEiTCCA3GgAwIBAgIUYxpKxPZIyG2n6qTPNESvYX/VpkowDQYJKoZIhvcNAQEL
BQAwfzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMREwDwYDVQQHDAhOZXcgWW9y
azEVMBMGA1UECgwMRXhhbXBsZSwgTExDMRgwFgYDVQQDDA9FeGFtcGxlIENvbXBh
bnkxHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20wHhcNMjAwMTA5MTM0
ODMyWhcNMzAwMTA2MTM0ODMyWjB/MQswCQYDVQQGEwJVUzELMAkGA1UECAwCTlkx
ETAPBgNVBAcMCE5ldyBZb3JrMRUwEwYDVQQKDAxFeGFtcGxlLCBMTEMxGDAWBgNV
BAMMD0V4YW1wbGUgQ29tcGFueTEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxl
LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL1SKznmggF6IaCF
4Jq+CHl9x8tmteQkws+ix65J2Id104fSibrRK8If3LMbKlrmXrpXFIl1TvDGPJQd
emcJhy3tFXR0eRqPTyqOfwxVy4AW7plMpemsoDrk8uONtwUdwmNNRsPeppIIEov7
aj6SWGLzFUjoKwHbXsfy2ff80/9EP7zkJr1ts6VPbPafExDKT225OoANlZ4B3bOG
bviWcP5+HuWUolA1wcyIqLXpc9Lw1M6NsC252sgje9IBpx1NhGe5QNAg5p3BA75/
jbOQH0qSo1xm9cV+FNQJpBybnZ5wuUEgsPJ87MtTIbr0cM5IiarUr/kvyg4sywDV
e07Aaw0CAwEAAaOB/DCB+TAdBgNVHQ4EFgQU9wRYbfo7sxyDITOZCK0H8udIaiww
HwYDVR0jBBgwFoAU9wRYbfo7sxyDITOZCK0H8udIaiwwCQYDVR0TBAIwADALBgNV
HQ8EBAMCBaAwcQYDVR0RBGowaIIOZnVua3doYWxlLnRlc3SCFG5vZGUxLmZ1bmt3
aGFsZS50ZXN0ghRub2RlMi5mdW5rd2hhbGUudGVzdIIUbm9kZTMuZnVua3doYWxl
LnRlc3SCCWxvY2FsaG9zdIIJMTI3LjAuMC4xMCwGCWCGSAGG+EIBDQQfFh1PcGVu
U1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsFAAOCAQEAmXD3
pjwYG4M4NTixkxs9KvdQE5yDqOMEh5ZMygA7/kRbKrYLaFgDYYsNlRFqJNz3sDLe
jTU663Eur5TdwTNiksa11VB3qKCrgQIzhjOavofF0ODfaNBtHtBWwEcpq0t2MnWP
kWot/kqpUcphbx5zyzqHHjiSnNUu16PS/lepNZyQIrfSy23+WIEYEiTbDYqS38SX
p8Pc+i9hQyeOwo4CYnuoPcIRtL/zsFl7WnWKVqXqr7w0PDWus226xO2ZMMLRkMi5
scufzyGBJAsedlCXIbJ+azYlZ2yTr98C7ffEA1PSuhO7wTUim/LUo0UBC/bs6wpc
ZxMkNLp6IaHhNEIeyA==
-----END CERTIFICATE-----

View File

@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC9Uis55oIBeiGg
heCavgh5fcfLZrXkJMLPoseuSdiHddOH0om60SvCH9yzGypa5l66VxSJdU7wxjyU
HXpnCYct7RV0dHkaj08qjn8MVcuAFu6ZTKXprKA65PLjjbcFHcJjTUbD3qaSCBKL
+2o+klhi8xVI6CsB217H8tn3/NP/RD+85Ca9bbOlT2z2nxMQyk9tuTqADZWeAd2z
hm74lnD+fh7llKJQNcHMiKi16XPS8NTOjbAtudrII3vSAacdTYRnuUDQIOadwQO+
f42zkB9KkqNcZvXFfhTUCaQcm52ecLlBILDyfOzLUyG69HDOSImq1K/5L8oOLMsA
1XtOwGsNAgMBAAECggEAAbgEQnNQTNkiAwYUIvOEui2lKbiWACtBRYdRzshG2fv8
3qfPrk2F2y5U359ohAjBZWmy+wiAnfj+xc16tgLFImqbnkIMc2xHqLhAeQkyXshW
hDfI7dUuYzp+5gf8WGSLxkEGWnLkCkFegbzXmxfTC5rvX4kUEuE9/Ay9Y938wr2E
26qdRGxtfVsnFFkLXmj50W3AyF6nBRqZsaS2x8JpHTdw7AjevpL/au2nz1p1rTK9
6cR/V4Hy+dtXLgm0mLdg1G+CJmanjqiweaD4+m91rFTagFIFKf/t5i4IZMu/BLT7
OuylxvEnvZH4p3aSOF1ME0Uv4n2Pzb7Iov/ZZ52/AQKBgQD4qnuj4V3ASXqsraMH
m5MtpBlKAZkngWFesi5ZFijgyutfbIcCPwFOGuXmcaTMj9HtTIwAki+mxkN87UmV
ZM+em2ZJz6srRGvIGN5CMJaJtOPdh3iMjI5QdefJ5gkk207YKzKVw4sw5C+tr4Sr
Uyf3K5ttL+CS5bo26CVXGLlpwQKBgQDC55wrgIzC1VDoFU0N2AZqU31tpP2DTIxc
eu4PqEMF0hjtTh4R5JHR827PmcW3VCaZ1+Fet8+yJ5nZTHWJlFyIg3dIyebn9dau
Yy256S+/1tq7ACmTzw3tn/125g4Is6Sz8yHdZ1YejHqyrK8nmyxuHJVEpWgLI+Ru
U9qQAQqcTQKBgAYb2hG6lZ0FsRfQ5DJppgH3CBADXgnUadnzsqPJoZN0KLgdaGur
tJKAoqk4nX3RAq07tizFappEQKAvDCG5akhRNQAXM/NKKQOvaLZjjy8u3HIyw8lg
IpbjbqBNIGhhYtx4ozN+rEq1MF6p8y5qSo8N6TGTfYbeUebLaS9skhGBAoGAcmZF
uRb8CAPzODYAg0awBUq6DVhRYPbWUBXrk48cv9bgwLEgXzo9CPGMshe9AG1JNvWK
l/Dl3Nj3qZ8CQl2trocTxcqUWMRoXPVjyoJ/f2eZ/TcMMHDQ6RAGUvqXdC4VV3Y3
A2B7IPUts6A+Ms4W1w654o//sMJBeyyG1g12b+UCgYEA9oLi1licSby9pGuuZXqf
q5zyGzM3adQzOrUNR+GTOAnoQD7tcz2jTvlmn0yv66NzBoy8FAD+UNOiMGipe8Au
1Y3XVCeYho0crCRJP3/fLLmjNe1P/Ijgujpb5jEgCA91opWSpqRVjIspGU0YOApU
jCCVQukqEnud65ur9FLD4a8=
-----END PRIVATE KEY-----

View File

@ -2,9 +2,13 @@
Funkwhale can be run in Docker containers for local development. You can work on any part of the Funkwhale codebase and run the container setup to test your changes. To work with Docker:
## Prerequisites
1. [Install Docker](https://docs.docker.com/install)
2. [Install docker compose](https://docs.docker.com/compose/install)
3. Clone the Funkwhale repository to your system. The `develop` branch is checked out by default
2. [Install Docker Compose](https://docs.docker.com/compose/install)
3. [Install mkcert](https://github.com/FiloSottile/mkcert#installation)
4. [Install pre-commit](https://pre-commit.com/#install)
5. Clone the Funkwhale repository to your system. The `develop` branch is checked out by default.
::::{tab-set}
@ -28,7 +32,16 @@ Funkwhale can be run in Docker containers for local development. You can work on
::::
## Set up your Docker environment
6. Activate the pre-commit hook:
```sh
pre-commit install
```
7. Finally, initialise the environment:
```sh
cp .env.example .env
```
## Set up the Docker environment
```{note}
Funkwhale provides a `compose.yml` file following the default file naming convention of a Docker Compose manifest. For Linux users, we assume that you finished the post-install steps to [manage Docker as a non-root user](https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user).
@ -36,69 +49,79 @@ Funkwhale provides a `compose.yml` file following the default file naming conven
To set up your Docker environment:
1. Create a `.env` file to enable customization of your setup.
```sh
touch .env
```
2. Add the following variables to load images and enable access to Django admin pages:
```text
MEDIA_URL=http://localhost:8000/media/
STATIC_URL=http://localhost:8000/staticfiles/
```
3. Create a network for federation support
1. Create a network for federation support:
```sh
docker network create federation
```
2. Then build the application containers. Run this command any time there are upstream changes or dependency changes to ensure you're up-to-date.
Once you've set everything up, you need to build the containers. Run this command any time there are upstream changes or dependency changes to ensure you're up-to-date.
```sh
docker compose build
```
## Set up auxiliary services
1. Create a wildcard certificate for `funkwhale.test` and `*.funkwhale.test` which will be installed into your system and browser trust stores with:
```sh
mkcert -install -cert-file compose/var/test.crt -key-file compose/var/test.key "funkwhale.test" "*.funkwhale.test"
```
Then run the network services to access the running containers.
2. Launch Træfik and dnsmasq using the bundled configuration:
```sh
docker compose -f compose.net.yml up -d
```
3. Add the DNS search domain for `~funkwhale.test` to your system. This allows your system to dereference our domain names `funkwhale.funkwhale.test`, `node2.funkwhale.test`, `node3.…`, `…` to the IP address of the Træfik reverse proxy listening at `172.17.0.1`.
::::{tab-set}
:::{tab-item} Linux
```sh
sudo resolvectl dns docker0 172.17.0.1
sudo resolvectl domain docker0 '~funkwhale.test.'
```
:::
:::{tab-item} Mac
Follow the instructions at [macOS: Using Custom DNS Resolvers · vNinja.net] (https://vninja.net/2020/02/06/macos-custom-dns-resolvers/)
:::
::::
:::{tip}
You can now reach your Træfik dashboard at [`http://funkwhale.test:8008/dashboard/#/http/routers`](http://funkwhale.test:8008/dashboard/#/http/routers).
:::
:::{note}
If your `docker0` network has no running containers presently attached to it, uncomment the `net.helpers.docker0.yml` rule in `compose.net.yml`.
Then restart the networking stack with `docker compose -f compose.net.yml up -d`.
:::
## Set up application services
Once you have set up the dependencies, launch all services to start working:
```sh
docker compose build
```
## Manage services
Once you have set up your containers, launch all services to start working on them:
::::{tab-set}
:::{tab-item} Multi node federation testnet (Default)
```sh
docker compose -f compose.net.yml up -d
docker compose up -d
```
Find instructions for starting multiple instances further below.
:::{tip}
This gives you access to the following:
- The Funkwhale web app on `https://funkwhale.funkwhale.test`
- The Funkwhale API on `https://funkwhale.funkwhale.test/api/v1`
- The Django admin interface on `https://funkwhale.funkwhale.test/api/admin`
- The Funkwhale web app on [`https://funkwhale.funkwhale.test`](https://funkwhale.funkwhale.test)
- The Funkwhale API on [`https://funkwhale.funkwhale.test/api/v1`](https://funkwhale.funkwhale.test/api/v1)
- The Django admin interface on [`https://funkwhale.funkwhale.test/api/admin`](https://funkwhale.funkwhale.test/api/admin)
:::
:::
:::{tab-item} Single node local development
```sh
docker compose -f compose.yml -f compose.local.yml up -d
```
This gives you access to the following:
- The Funkwhale web app on `http://localhost:8000`
- The Funkwhale API on `http://localhost:8000/api/v1`
- The Django admin interface on `http://localhost:8000/api/admin`
:::
::::
To be able to login create a local superuser:
Create a local superuser to be able to login:
```sh
docker compose run --rm api funkwhale-manage fw users create --superuser
@ -116,13 +139,14 @@ If you want to destroy your containers, run the following:
docker compose down
```
To also destroy the state of your containers, run:
Destroy the state of your containers:
```sh
docker compose down -v
docker compose down --volumes
rm -rf .state/
```
## Set up local data
### Set up local data for development
You can create local data to mimic a live environment.
@ -134,101 +158,22 @@ command="from funkwhale_api.music import fake_data; fake_data.create_data($artis
echo $command | docker compose run --rm -T api funkwhale-manage shell -i python
```
## Set up federation support
### Running multiple instances
Working on federation features requires additional setup. You need to do the following:
1. Update your DNS resolver to resolve all your `.test` hostnames locally
2. Set up a reverse proxy (such as traefik) to catch `.test` requests with a TLS certificate
3. Set up two or more local instances
To resolve hostnames locally, run the following:
::::{tab-set}
:::{tab-item} dnsmasq
Set up as many different projects as you need. Make sure the `COMPOSE_PROJECT_NAME` and `VUE_PORT` variables are unique per instance
```sh
echo "address=/test/172.17.0.1" | sudo tee /etc/dnsmasq.d/test.conf
sudo systemctl restart dnsmasq
export COMPOSE_PROJECT_NAME=node2
# VUE_PORT this has to be unique for each instance
export VUE_PORT=1234
docker compose run --rm api funkwhale-manage fw users create --superuser
docker compose up -d
```
:::
You can access your project at `https://{COMPOSE_PROJECT_NAME}.funkwhale.test`.
:::{tab-item} NetworkManager
:::{warning}
Federation between Alpine containers in Docker is broken due to upstream errors.
```sh
echo "address=/test/172.17.0.1" | sudo tee /etc/NetworkManager/dnsmasq.d/test.conf
sudo systemctl restart NetworkManager
```
:::
:::{tab-item} dnsmasq in Docker
```sh
docker compose -f docker/dnsmasq.yml up -d
sudo resolvectl domain docker0 '~funkwhale.test.'
sudo resolvectl dns docker0 172.17.0.1
```
:::
::::
To add a wildcard certificate, copy the test certificate from the `docker/ssl` folder to your system store. This certificate is a wildcard for `*.funkwhale.test`.
For Debian-based systems like Ubuntu, run:
```sh
sudo cp docker/ssl/test.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
```
For RHEL-based systems like Fedora, run:
```sh
sudo cp docker/ssl/test.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust
```
To run a reverse proxy for your app:
1. Add the following configuration to your `.env` file:
```sh
cat >> .env <<< "
# Remove any port binding so you can specify this per-instance
VUE_PORT_BINDING=
# Disable certificate validation
EXTERNAL_REQUESTS_VERIFY_SSL=false
# Ensure all links use https
FUNKWHALE_PROTOCOL=https
# Disable host ports binding for the nginx container so that traefik handles everything
NGINX_PORTS_MAPPING=80"
```
2. Launch traefik using the bundled configuration:
```sh
docker compose -f docker/traefik.yml up -d
```
Your previous instance is now reachable at https://funkwhale.funkwhale.test
3. Set up as many different projects as you need. Make sure the `COMPOSE_PROJECT_NAME` and `VUE_PORT` variables are unique per instance
```sh
export COMPOSE_PROJECT_NAME=node2
# VUE_PORT this has to be unique for each instance
export VUE_PORT=1234
docker compose run --rm api funkwhale-manage fw users create --superuser
docker compose up -d
```
You can access your project at `https://{COMPOSE_PROJECT_NAME}.funkwhale.test`.
## Known issues and workarounds
- (systemd-resolved) Under certain conditions the `docker0` bridge does not stay up, which in turn deactivates any DNS configuration associated to the interface. Uncomment the prepared resolved helper in line #6 of `compose.net.yml` to fix this issue and restart the networking stack. `docker compose -f compose.net.yml up -d`
- Broken federation on Alpine containers
- [Error while fetching the library: musl + getaddrinfo()](https://docs.allmende.io/s/03534f44-9514-40b8-a40a-df4a027b908b) (German)
:::