Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ If you would like to add your own config, you can use the [service-template](tem
| 🎶 **Navidrome** | Your Personal Streaming Service self-hosted. | [Details](services/navidrome) |
| 🎶 **Swing Music** | A fast, beautiful, self-hosted music streaming server for your local audio library. | [Details](services/swingmx) |
| 🎬 **Overseerr** | A request management and media discovery tool for Plex and Jellyfin users. | [Details](services/overseerr) |
| 🎵 **Picard** | MusicBrainz Picard is a cross-platform music tagger for organizing and tagging music files. | [Details](services/picard) |
| 🎬 **Plex** | A media server that organizes video, music, and photos from personal media libraries. | [Details](services/plex) |
| 📥 **qBittorrent** | An open-source BitTorrent client. | [Details](services/qbittorrent) |
| 📡 **Prowlarr** | An indexer manager and proxy for applications like Radarr, Sonarr, and Lidarr. | [Details](services/prowlarr) |
Expand Down
17 changes: 17 additions & 0 deletions services/picard/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#version=1.1
#URL=https://github.com/tailscale-dev/ScaleTail
#COMPOSE_PROJECT_NAME= # Optional: only use when running multiple deployments on the same infrastructure.

# Service Configuration
SERVICE=picard # Service name (e.g., adguard). Used as hostname in Tailscale and for container naming (app-${SERVICE}).
IMAGE_URL=mikenye/picard # Docker image URL from container registry (e.g., adguard/adguard-home).

# Network Configuration
SERVICEPORT=5800 # Port to expose to local network. Uncomment the "ports:" section in compose.yaml to enable.
DNS_SERVER=9.9.9.9 # Preferred DNS server for Tailscale. Uncomment the "dns:" section in compose.yaml to enable.

# Tailscale Configuration
TS_AUTHKEY= # Auth key from https://tailscale.com/admin/authkeys. See: https://tailscale.com/kb/1085/auth-keys#generate-an-auth-key for instructions.

# Optional Service variables
# PUID=1000
40 changes: 40 additions & 0 deletions services/picard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# MusicBrainz Picard with Tailscale Sidecar Configuration

This Docker Compose setup deploys **MusicBrainz Picard** alongside a **Tailscale sidecar container**, allowing secure access to your self-hosted music tagging and metadata management environment over your private **Tailscale network**. With this setup, Picard remains **private and reachable only from trusted devices within your Tailnet**, ensuring your media metadata library stays secure and isolated from the public internet.

## MusicBrainz Picard

[**MusicBrainz Picard**](https://picard.musicbrainz.org/) is the official cross-platform tag editor from [MusicBrainz](https://musicbrainz.org/). It uses the community-maintained MusicBrainz database to identify, tag, and organize your music files with accurate and rich metadata — including artist information, album art, release data, and more.

Picard supports a wide range of audio formats and integrates powerful plugins to streamline batch processing, fingerprinting (via AcoustID), and custom tagging workflows.

## Key Features

- 🎵 **Accurate Tagging** – Automatically identify and tag music files using MusicBrainz metadata.
- 🧠 **AcoustID Matching** – Use audio fingerprints to detect and tag tracks even without metadata.
- 🖼️ **Album Art Integration** – Fetch and embed high-quality cover art automatically.
- ⚙️ **Plugin Support** – Extend functionality with community or custom plugins.
- 📁 **Batch Processing** – Organize entire libraries with flexible renaming and folder rules.
- 🐳 **Docker-Ready** – Simple to deploy and run in containers.
- 🔐 **Private Access via Tailscale** – Keep your tagging environment accessible only on your Tailnet.
- 📦 **Open Source** – Actively maintained and community-driven.

## Why Self-Host?

When you manage large local music libraries, you may prefer **full privacy and control** over which metadata services your files connect to. Self-hosting Picard behind Tailscale offers:

- No exposure of ports to the public internet.
- Private access to your tagging environment from any authorized Tailscale device.
- A streamlined tagging workflow fully contained within your home media infrastructure.

With this setup, your tagging process is secured and contained — perfect for privacy-conscious audiophiles and homelab enthusiasts.

## Configuration Overview

In this deployment, a **Tailscale sidecar container** (for example `tailscale-picard`) connects your Picard instance to your private Tailnet. The main `picard` container uses:

```plain
network_mode: service:tailscale-picard
```

This means all Picard traffic — web interface, plugin updates, and library calls — travels securely through Tailscale.
71 changes: 71 additions & 0 deletions services/picard/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
configs:
ts-serve:
content: |
{"TCP":{"443":{"HTTPS":true}},
"Web":{"$${TS_CERT_DOMAIN}:443":
{"Handlers":{"/":
{"Proxy":"http://127.0.0.1:5800"}}}},
"AllowFunnel":{"$${TS_CERT_DOMAIN}:443":false}}

services:
# Make sure you have updated/checked the .env file with the correct variables.
# All the ${ xx } need to be defined there.
# Tailscale Sidecar Configuration
tailscale:
image: tailscale/tailscale:latest # Image to be used
container_name: tailscale-${SERVICE} # Name for local container management
hostname: ${SERVICE} # Name used within your Tailscale environment
environment:
- TS_AUTHKEY=${TS_AUTHKEY}
- TS_STATE_DIR=/var/lib/tailscale
- TS_SERVE_CONFIG=/config/serve.json # Tailscale Serve configuration to expose the web interface on your local Tailnet - remove this line if not required
- TS_USERSPACE=false
- TS_ENABLE_HEALTH_CHECK=true # Enable healthcheck endpoint: "/healthz"
- TS_LOCAL_ADDR_PORT=127.0.0.1:41234 # The <addr>:<port> for the healthz endpoint
#- TS_ACCEPT_DNS=true # Uncomment when using MagicDNS
configs:
- source: ts-serve
target: /config/serve.json
volumes:
- ./config:/config # Config folder used to store Tailscale files - you may need to change the path
- ./ts/state:/var/lib/tailscale # Tailscale requirement - you may need to change the path
devices:
- /dev/net/tun:/dev/net/tun # Network configuration for Tailscale to work
cap_add:
- net_admin # Tailscale requirement
#ports:
# - 0.0.0.0:${SERVICEPORT}:${SERVICEPORT} # Binding port ${SERVICE}PORT to the local network - may be removed if only exposure to your Tailnet is required
# If any DNS issues arise, use your preferred DNS provider by uncommenting the config below
#dns:
# - ${DNS_SERVER}
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:41234/healthz"] # Check Tailscale has a Tailnet IP and is operational
interval: 1m # How often to perform the check
timeout: 10s # Time to wait for the check to succeed
retries: 3 # Number of retries before marking as unhealthy
start_period: 10s # Time to wait before starting health checks
restart: always

# ${SERVICE}
application:
image: ${IMAGE_URL} # Image to be used
network_mode: service:tailscale # Sidecar configuration to route ${SERVICE} through Tailscale
container_name: app-${SERVICE} # Name for local container management
environment:
- USER_ID=1000
- GROUP_ID=1000
- TZ=Europe/Amsterdam # Change according to your timezone or set by mapping /etc/localtime between the host and the container.
volumes:
- ./${SERVICE}-data/config:/config:rw
- ./${SERVICE}-data/music:/config:rw
depends_on:
tailscale:
condition: service_healthy
healthcheck:
test: ["CMD", "pgrep", "-f", "${SERVICE}"] # Check if ${SERVICE} process is running
interval: 1m # How often to perform the check
timeout: 10s # Time to wait for the check to succeed
retries: 3 # Number of retries before marking as unhealthy
start_period: 30s # Time to wait before starting health checks
restart: always