My traefik.yml
version: "3.7"
x-command: &command
command:
# Docker swarm configuration
# - "--providers.docker.endpoint=unix:///var/run/docker.sock"
- "--global.checknewversion=false"
- "--global.sendanonymoususage=false"
- "--providers.docker.endpoint=http://socketproxy:2375"
- "--providers.docker.swarmMode=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=traefik"
# Configure entrypoint
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
# - "--entrypoints.websecure.http.middlewares=crowdsec-bouncer, globalerror"
# ## Enable this to allow access to endpoints through Authelia rather than defining all authelia participants through labels.
# - "--entrypoints.websecure.http.middlewares=crowdsec-bouncer, globalerror, authelia"
# - "--entrypoints.websecure.http.middlewares=globalerror, crowdsec-bouncer"
# - "--entrypoints.websecure.http.middlewares=globalerror"
# SSL configuration
- "--certificatesresolvers.letsencryptresolver.acme.httpchallenge=true"
- "--certificatesresolvers.letsencryptresolver.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencryptresolver.acme.email=admin@example.com"
- "--certificatesresolvers.letsencryptresolver.acme.storage=/letsencrypt/acme.json"
# Global HTTP -> HTTPS
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
# Enable dashboard
- "--api.dashboard=true"
services:
traefik:
image: traefik:v2.6
<<: *command
ports:
- target: 80
published: 80
protocol: tcp
mode: host
- target: 443
published: 443
protocol: tcp
mode: host
volumes:
# To persist certificates
- /mnt/tank/persist/example.com/traefik/production/config:/letsencrypt
# So that Traefik can listen to the Docker events
#- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- traefik
- socketproxy
deploy:
placement:
constraints:
- node.hostname == ingress.example.com
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.tls=true"
- "traefik.http.services.traefik.loadbalancer.server.port=888" # required by swarm but not used.
- "traefik.http.routers.traefik.rule=Host(`monitor-ingress.example.com`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls.certresolver=letsencryptresolver"
- "traefik.http.routers.traefik.service=api@internal"
update_config:
order: start-first
failure_action: rollback
delay: 5s
delay: 10s
parallelism: 1
restart_policy:
condition: on-failure
Then this is my funkwhale.yml
version: "3.9"
x-environment: &environment
environment:
FUNKWHALE_VERSION: 1.2.7
FUNKWHALE_API_IP: 127.0.0.1
FUNKWHALE_API_PORT: 5000
FUNKWHALE_WEB_WORKERS: 4
FUNKWHALE_HOSTNAME: whale.example.com
FUNKWHALE_PROTOCOL: http
LOGLEVEL: error
REVERSE_PROXY_TYPE: nginx
MEDIA_ROOT: /srv/funkwhale/data/media
STATIC_ROOT: /srv/funkwhale/data/static
DJANGO_SETTINGS_MODULE: config.settings.production
DJANGO_SECRET_KEY: REDACTED
MUSIC_DIRECTORY_PATH: /srv/funkwhale/data/music
MUSIC_DIRECTORY_SERVE_PATH: /srv/funkwhale/data/music
FUNKWHALE_FRONTEND_PATH: /srv/funkwhale/front/dist
NGINX_MAX_BODY_SIZE: 100M
FUNKWHALE_URL: whale.example.com
# AWS_ACCESS_KEY_ID:
# AWS_SECRET_ACCESS_KEY:
# AWS_STORAGE_BUCKET_NAME:
C_FORCE_ROOT: "true"
POSTGRES_HOST_AUTH_METHOD: trust
NGINX_MAX_BODY_SIZE: 100M
services:
postgres:
networks:
- default
<<: *environment
image: postgres:11
volumes:
- /mnt/tank/persist/example.com/whale/production/data/postgres:/var/lib/postgresql/data
deploy:
replicas: 1
placement:
constraints:
- node.labels.home-rack == true
labels:
- "traefik.enable=false"
redis:
networks:
- default
<<: *environment
image: redis:5
volumes:
- /mnt/tank/persist/example.com/whale/production/data/redis:/data
deploy:
replicas: 1
placement:
constraints:
- node.labels.home-rack == true
labels:
- "traefik.enable=false"
celeryworker:
image: funkwhale/funkwhale:latest
networks:
- default
depends_on:
- postgres
- redis
# Celery workers handle background tasks (such file imports or federation
# messaging). The more processes a worker gets, the more tasks
# can be processed in parallel. However, more processes also means
# a bigger memory footprint.
# By default, a worker will span a number of process equal to your number
# of CPUs. You can adjust this, by explicitly setting the --concurrency
# flag:
# celery -A funkwhale_api.taskapp worker -l INFO --concurrency=4
command: celery -A funkwhale_api.taskapp worker -l INFO --concurrency=${CELERYD_CONCURRENCY-0}
<<: *environment
volumes:
- "/mnt/tank/persist/example.com/whale/production/data/music:/srv/funkwhale/data/music:ro"
- "/mnt/tank/persist/example.com/whale/production/data/media:/srv/funkwhale/data/media"
deploy:
replicas: 1
placement:
constraints:
- node.labels.home-rack == true
labels:
- "traefik.enable=false"
celerybeat:
image: funkwhale/funkwhale:latest
networks:
- default
depends_on:
- postgres
- redis
<<: *environment
command: celery -A funkwhale_api.taskapp beat --pidfile= -l INFO
deploy:
replicas: 1
placement:
constraints:
- node.labels.home-rack == true
labels:
- "traefik.enable=false"
api:
image: funkwhale/funkwhale:latest
networks:
- default
depends_on:
- postgres
- redis
<<: *environment
volumes:
- "/mnt/tank/persist/example.com/whale/production/data/music:/srv/funkwhale/data/music:ro"
- "/mnt/tank/persist/example.com/whale/production/data/media:/srv/funkwhale/data/media"
- "/mnt/tank/persist/example.com/whale/production/data/static:/srv/funkwhale/data/static"
- "/mnt/tank/persist/example.com/whale/production/front/dist:/frontend"
deploy:
replicas: 1
placement:
constraints:
- node.labels.home-rack == true
labels:
- "traefik.enable=false"
nginx:
image: nginx
networks:
- default
depends_on:
- api
<<: *environment
volumes:
- "/mnt/tank/persist/example.com/whale/production/nginx/funkwhale.template:/etc/nginx/conf.d/funkwhale.template:ro"
- "/mnt/tank/persist/example.com/whale/production/nginx/funkwhale_proxy.conf:/etc/nginx/funkwhale_proxy.conf:ro"
- "/mnt/tank/persist/example.com/whale/production/data/music:/srv/funkwhale/data/music:ro"
- "/mnt/tank/persist/example.com/whale/production/data/media:/srv/funkwhale/data/media:ro"
- "/mnt/tank/persist/example.com/whale/production/data/static:/srv/funkwhale/data/static:ro"
- "/mnt/tank/persist/example.com/whale/production/front/dist:/frontend:ro"
command: >
sh -c "envsubst \"`env | awk -F = '{printf \" $$%s\", $$1}'`\"
< /etc/nginx/conf.d/funkwhale.template
> /etc/nginx/conf.d/default.conf
&& cat /etc/nginx/conf.d/default.conf
&& nginx -g 'daemon off;'"
deploy:
replicas: 1
placement:
constraints:
- node.labels.home-rack == true
labels:
- "traefik.enable=true"
- "traefik.http.routers.whale.tls=true"
- "traefik.http.services.whale.loadbalancer.server.port=80"
- "traefik.http.routers.whale.rule=Host(`whale.example.com`)"
- "traefik.http.routers.whale.entrypoints=websecure"
- "traefik.http.routers.whale.tls.certresolver=letsencryptresolver"
- "traefik.http.routers.whale.service=whale"
- "traefik.docker.network=traefik"
networks:
- default
- traefik
networks:
traefik:
external: true
default:
external: false
I booted this and prepped it all using just the instructions from https://docs.funkwhale.audio/installation/docker.html#multi-container-installation which resulted in a workable page loading on a sub port :5000 however I'd really like to shove this whole stack behind Traefik for automatic TLS acquisition and https connection upgrades. I'm just getting a 500 Server Error and no useful logs from Nginx.
Where do I start here?
upstream funkwhale-api {
# depending on your setup, you may want to update this
server api:5000;
}
# required for websocket support
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name whale.example.com;
# TLS
# Feel free to use your own configuration for SSL here or simply remove the
# lines and move the configuration to the previous server block if you
# don't want to run funkwhale behind https (this is not recommended)
# have a look here for let's encrypt configuration:
# https://certbot.eff.org/all-instructions/#debian-9-stretch-nginx
root /frontend;
# If you are using S3 to host your files, remember to add your S3 URL to the
# media-src and img-src headers (e.g. img-src 'self' https://<your-S3-URL> data:)
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; object-src 'none'; media-src 'self' data:";
add_header Referrer-Policy "strict-origin-when-cross-origin";
add_header X-Frame-Options "SAMEORIGIN" always;
location / {
include /etc/nginx/funkwhale_proxy.conf;
# this is needed if you have file import via upload enabled
client_max_body_size 100M;
proxy_pass http://funkwhale-api/;
}
location /front/ {
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; object-src 'none'; media-src 'self' data:";
add_header Referrer-Policy "strict-origin-when-cross-origin";
add_header Service-Worker-Allowed "/";
alias /frontend/;
expires 30d;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
location /front/embed.html {
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; object-src 'none'; media-src 'self' data:";
add_header Referrer-Policy "strict-origin-when-cross-origin";
add_header X-Frame-Options "" always;
alias /frontend/embed.html;
expires 30d;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
location /federation/ {
include /etc/nginx/funkwhale_proxy.conf;
proxy_pass http://funkwhale-api/federation/;
}
# You can comment this if you do not plan to use the Subsonic API
location /rest/ {
include /etc/nginx/funkwhale_proxy.conf;
proxy_pass http://funkwhale-api/api/subsonic/rest/;
}
location /.well-known/ {
include /etc/nginx/funkwhale_proxy.conf;
proxy_pass http://funkwhale-api/.well-known/;
}
location /media/ {
alias /srv/funkwhale/data/media/;
}
# this is an internal location that is used to serve
# audio files once correct permission / authentication
# has been checked on API side
location /_protected/media {
internal;
alias /srv/funkwhale/data/media;
}
# Comment the previous location and uncomment this one if you're storing
# media files in a S3 bucket
# location ~ /_protected/media/(.+) {
# internal;
# # Needed to ensure DSub auth isn't forwarded to S3/Minio, see #932
# proxy_set_header Authorization "";
# proxy_pass $1;
# }
location /_protected/music {
# this is an internal location that is used to serve
# audio files once correct permission / authentication
# has been checked on API side
# Set this to the same value as your MUSIC_DIRECTORY_PATH setting
internal;
alias /srv/funkwhale/data/music;
}
location /staticfiles/ {
# django static files
alias ${STATIC_ROOT}/;
}
}