From bb7d32a2f24459ce43aaa7fb1822f32d637e420a Mon Sep 17 00:00:00 2001 From: Nicolas Binette Date: Tue, 16 Jun 2026 09:47:15 -0400 Subject: [PATCH] Add AzuraCast community container (#8176) * Add AzuraCast community container Signed-off-by: Nicolas Binette * Update Caddy readme to mention AzuraCast Signed-off-by: Nicolas Binette * azuracast: consolidate storage/* volumes into single storage volume Replace seven granular mounts under /var/azuracast/storage with a single nextcloud_aio_azuracast_storage volume, matching AzuraCast's official docker-compose layout. Remove nextcloud_aio_azuracast_uploads from backup_volumes (media files are captured via stations and AzuraCast's own backup archives in /var/azuracast/backups). Signed-off-by: Nicolas Binette * azuracast: change HTTP/HTTPS ports to 10080/10443, expose on host Use ports recommended by AzuraCast docs for reverse proxy deployments. Expose port 10080 (HTTP) with %APACHE_IP_BINDING% following the vaultwarden pattern, and port 10443 (HTTPS) on all interfaces for direct access. Update readme accordingly. Signed-off-by: Nicolas Binette * azuracast: replace shared volume with %NEXTCLOUD_MOUNT%, document filesystem sharing Replace the named volume nextcloud_aio_azuracast_shared with the AIO-native %NEXTCLOUD_MOUNT% mechanism. The volume is silently skipped if NEXTCLOUD_MOUNT is not configured in AIO. Update readme.md: - Document NEXTCLOUD_MOUNT as the advanced file sharing approach, with setup instructions and a comparison to the SFTP approach - Clarify default access behavior: files (mode 644) are world-readable by both processes; some AzuraCast directories (mode 700) require intervention - Document POSIX ACL commands for unlocking read-only or bidirectional access on specific paths, with a note that they must be re-run after structural changes by AzuraCast - Minor wording and formatting improvements throughout Tested on a live AzuraCast instance: rename and bidirectional move confirmed working after ACL application; containers start correctly without UMASK override. Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Nicolas Binette * Update community-containers/azuracast/azuracast.json Do not expose internal HTTP port 10080 on host. Co-authored-by: Simon L. Signed-off-by: Nicolas Binette * azuracast: add to community containers overview diagram Add AzuraCast entry to the Media group of the mermaid overview diagram in community-containers/readme.md, as requested by szaimen. Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Nicolas Binette * fix the json Signed-off-by: Simon L. * Apply suggestion from @szaimen Signed-off-by: Simon L. * Apply suggestion from @szaimen Signed-off-by: Simon L. --------- Signed-off-by: Nicolas Binette Signed-off-by: Simon L. Co-authored-by: Claude Sonnet 4.6 Co-authored-by: Simon L. --- community-containers/azuracast/azuracast.json | 82 ++++++++++++ community-containers/azuracast/readme.md | 119 ++++++++++++++++++ community-containers/caddy/readme.md | 4 +- community-containers/readme.md | 1 + 4 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 community-containers/azuracast/azuracast.json create mode 100644 community-containers/azuracast/readme.md diff --git a/community-containers/azuracast/azuracast.json b/community-containers/azuracast/azuracast.json new file mode 100644 index 00000000..eb9055c6 --- /dev/null +++ b/community-containers/azuracast/azuracast.json @@ -0,0 +1,82 @@ +{ + "aio_services_v1": [ + { + "container_name": "nextcloud-aio-azuracast", + "display_name": "AzuraCast", + "documentation": "https://github.com/nextcloud/all-in-one/tree/main/community-containers/azuracast", + "image": "ghcr.io/azuracast/azuracast", + "image_tag": "stable", + "internal_port": "10080", + "restart": "unless-stopped", + "ports": [ + { + "ip_binding": "%APACHE_IP_BINDING%", + "port_number": "10443", + "protocol": "tcp" + }, + { + "ip_binding": "", + "port_number": "2022", + "protocol": "tcp" + }, + { "ip_binding": "", "port_number": "8000", "protocol": "tcp" }, + { "ip_binding": "", "port_number": "8005", "protocol": "tcp" }, + { "ip_binding": "", "port_number": "8006", "protocol": "tcp" }, + { "ip_binding": "", "port_number": "8010", "protocol": "tcp" }, + { "ip_binding": "", "port_number": "8015", "protocol": "tcp" }, + { "ip_binding": "", "port_number": "8016", "protocol": "tcp" }, + { "ip_binding": "", "port_number": "8020", "protocol": "tcp" }, + { "ip_binding": "", "port_number": "8025", "protocol": "tcp" }, + { "ip_binding": "", "port_number": "8026", "protocol": "tcp" }, + { "ip_binding": "", "port_number": "8030", "protocol": "tcp" }, + { "ip_binding": "", "port_number": "8035", "protocol": "tcp" }, + { "ip_binding": "", "port_number": "8036", "protocol": "tcp" }, + { "ip_binding": "", "port_number": "8040", "protocol": "tcp" }, + { "ip_binding": "", "port_number": "8045", "protocol": "tcp" }, + { "ip_binding": "", "port_number": "8046", "protocol": "tcp" } + ], + "environment": [ + "TZ=%TIMEZONE%", + "AZURACAST_HTTP_PORT=10080", + "AZURACAST_HTTPS_PORT=10443", + "MARIADB_ROOT_PASSWORD=%AZURACAST_DB_PASSWORD%" + ], + "secrets": [ + "AZURACAST_DB_PASSWORD" + ], + "ui_secret": "AZURACAST_DB_PASSWORD", + "volumes": [ + { + "source": "nextcloud_aio_azuracast_stations", + "destination": "/var/azuracast/stations", + "writeable": true + }, + { + "source": "nextcloud_aio_azuracast_db", + "destination": "/var/lib/mysql", + "writeable": true + }, + { + "source": "nextcloud_aio_azuracast_storage", + "destination": "/var/azuracast/storage", + "writeable": true + }, + { + "source": "nextcloud_aio_azuracast_backups", + "destination": "/var/azuracast/backups", + "writeable": true + }, + { + "source": "%NEXTCLOUD_MOUNT%", + "destination": "%NEXTCLOUD_MOUNT%", + "writeable": true + } + ], + "backup_volumes": [ + "nextcloud_aio_azuracast_stations", + "nextcloud_aio_azuracast_db", + "nextcloud_aio_azuracast_backups" + ] + } + ] +} diff --git a/community-containers/azuracast/readme.md b/community-containers/azuracast/readme.md new file mode 100644 index 00000000..83c79478 --- /dev/null +++ b/community-containers/azuracast/readme.md @@ -0,0 +1,119 @@ +## AzuraCast + +This container bundles [AzuraCast](https://www.azuracast.com/), an open-source web radio management suite, and integrates it with Nextcloud AIO. + +### Notes + +- To access AzuraCast from outside your local network, use the [Caddy community container](https://github.com/nextcloud/all-in-one/tree/main/community-containers/caddy), which will automatically configure `radio.$NC_DOMAIN` to reverse-proxy the AzuraCast interface. Make sure to point `radio.your-nc-domain.com` to your server using an A or CNAME record before starting. +- The AzuraCast web interface is then available at `https://radio.your-nc-domain.com`. On first start, you will be directed to `/setup/register` to create the admin account. +- **Radio streaming ports** (8000–8046) cover up to 5 stations that are exposed directly on the host without reverse-proxy. +- **SFTP access** is available on port 2022. +- AzuraCast's data (stations, database, backups) is automatically included in AIO's BorgBackup solution. +- **Updater:** The standard AzuraCast `updater` container is omitted — updates are managed through AIO's standard container update mechanism (pulling the new `ghcr.io/azuracast/azuracast:stable` image). +- AzuraCast uses port **10080** (HTTP) and **10443** (HTTPS), following the [ports recommended by AzuraCast](https://www.azuracast.com/docs/administration/multi-site-installation/#edit-azuracast-web-serving-ports) for reverse proxy deployments. Both ports are exposed directly on the host. The recommended way to access the web interface is via `https://radio.your-nc-domain.com` through the Caddy community container. Direct HTTPS access is also available at `https://yourserver:10443` (self-signed certificate — browser warning expected). +- Custom domains can be configured using [caddy](https://github.com/nextcloud/all-in-one/tree/main/community-containers/caddy) + +### Recommended settings after first login + +On first access, AzuraCast will prompt you to create an admin account, then redirect to a **System Settings** page. The following settings are recommended when running behind the Caddy community container: + +**Settings tab:** +- **Site Base URL**: Set to `https://radio.your-nc-domain.com` +- **Use Web Proxy for Radio**: Enable — all radio traffic is routed securely through Caddy +- **Use High-Performance Now Playing Updates**: Enable — activates WebSocket, SSE, and static JSON updates for metadata (fully supported by Caddy) + +**Security & Privacy tab:** +- **Always Use HTTPS**: Enable +- **IP Address Source**: Select `Reverse Proxy (X-Forwarded-For)` + +**Services tab:** +- **LetsEncrypt**: Leave empty — TLS certificates are handled by Caddy + +### Streaming ports + +The following ports are exposed for up to 5 radio stations (3 ports per station: stream, remote DJ, legacy SHOUTcast): + +| Station | Stream | Remote DJ | SHOUTcast | +|---------|--------|-------|-----------| +| 1 | 8000 | 8005 | 8006 | +| 2 | 8010 | 8015 | 8016 | +| 3 | 8020 | 8025 | 8026 | +| 4 | 8030 | 8035 | 8036 | +| 5 | 8040 | 8045 | 8046 | + +Listeners and live source (remote DJs) can connect to these ports directly. Ports are assigned sequentially to new stations, but can be configured manually in `/admin/stations`. + +By enabling **Web Proxy for Radio** (recommended settings), you can create an unlimited number of stations without direct port access. Assign the available ports to stations that actually need them. + +### Known limitations + +- The `updater` container from the standard AzuraCast docker-compose is not included (requires Docker socket access, incompatible with AIO's security model). +- The `shoutcast2`, `stereo_tool`, `rsas`, and `geolite` optional install directories are part of the unified `storage` volume. The corresponding features (SHOUTcast 2, Stereo Tool, RSAS, GeoLite2 geolocation) must be installed and activated manually from within AzuraCast after the container is running. + +#### Nextcloud file integration + +By default, AzuraCast runs in an isolated container: Nextcloud files are not accessible from within AzuraCast, and AzuraCast media files are not browsable in Nextcloud. + +**Nextcloud External Storage via SFTP** + +AzuraCast includes a built-in SFTP server (SFTPGo) on port 2022. SFTP users are managed per-station in AzuraCast under **Media → SFTP Users**. This lets each station operator define their own Nextcloud External Storage mount with their own credentials, without any host-level configuration. + +In Nextcloud, add an External Storage mount of type **SFTP** with the following parameters: + +| Field | Value | +|---|---| +| Host | `nextcloud-aio-azuracast` (within the Docker network) or your external domain/IP | +| Port | `2022` | +| Username / Password | As configured in AzuraCast's SFTP user settings | +| Root | Leave empty or set to the station's media subfolder | + +> **Note:** Do not use `localhost` as the host — within the Nextcloud container, `localhost` refers to Nextcloud itself, not AzuraCast. Use the container name `nextcloud-aio-azuracast` or your server's domain name instead. + +This approach supports per-station access control, works with both local and remote AzuraCast instances, and media files remain covered by AIO's BorgBackup solution. + +**Advanced: shared filesystem via `NEXTCLOUD_MOUNT`** + +`NEXTCLOUD_MOUNT` is an [AIO setting](https://github.com/nextcloud/all-in-one#how-to-allow-the-nextcloud-container-to-access-directories-on-the-host) that exposes an arbitrary host directory to the Nextcloud container, enabling **Nextcloud External Storage** mounts on the host filesystem. When set, the same path is automatically mounted in AzuraCast at the same location, giving both processes direct access to the same files — with significantly better performance than SFTP when managing large media libraries. + +To set this up: +1. Set `NEXTCLOUD_MOUNT` to a host directory path in AIO settings (e.g. `/data/media`). +2. In AzuraCast, configure a station to use a subdirectory of that path as its media storage (e.g. `/data/media/stations/mystation/media`). +3. In Nextcloud, optionally add a **Local** External Storage mount pointing to the same path to browse and manage the files from Nextcloud. + +If `NEXTCLOUD_MOUNT` is not configured in AIO, this volume is silently skipped and AzuraCast starts normally. + +> **Note:** Files in the shared directory are not included in AIO's BorgBackup. Back up this directory separately if needed. + +**Default access** + +Both processes run as different users — Nextcloud as `www-data` (UID 33) and AzuraCast as `azuracast` (UID 1000) — with no group membership in common. + +- Files created by either process (mode `644`) are readable by the other as world-readable, but cannot be modified. +- Directories created by Nextcloud (mode `755`) are browsable by AzuraCast. +- **Some AzuraCast directories are created with mode `700`** (user-created subdirectories). These cannot be listed or entered by Nextcloud without intervention. + +**Unlocking access** + +The following commands are run **on the host**. To grant access to a specific path — for example, after creating a new station — run: + +```bash +# Install ACL tools if not already present (Debian/Ubuntu) +sudo apt install acl + +# Read-only access for Nextcloud to an AzuraCast directory +sudo setfacl -R -m u:33:rX /data/media/stations/mystation/ + +# Bidirectional read/write access +sudo setfacl -R -m u:33:rwX,u:1000:rwX /data/media/stations/mystation/ +sudo setfacl -R -d -m u:33:rwX,u:1000:rwX /data/media/stations/mystation/ +``` + +> **Note:** These commands apply to the current directory tree. They need to be re-run when AzuraCast creates new subdirectories within the affected path. + +### Repository + +https://github.com/AzuraCast/AzuraCast + +### Maintainer + +https://github.com/biguenique diff --git a/community-containers/caddy/readme.md b/community-containers/caddy/readme.md index 68da1f92..cd8563a0 100644 --- a/community-containers/caddy/readme.md +++ b/community-containers/caddy/readme.md @@ -7,7 +7,8 @@ It also covers [lldap](https://github.com/nextcloud/all-in-one/tree/main/communi It also covers [nocodb](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nocodb) by listening on `tables.$NC_DOMAIN`, if installed. It also covers [seerr](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyseerr) by listening on `requests.$NC_DOMAIN`, if installed. It also covers [nextcloud-exporter](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nextcloud-exporter) by listening on `metrics.$NC_DOMAIN`, if installed. -It also covers [LocalAI](https://github.com/nextcloud/all-in-one/tree/main/community-containers/local-ai) by listening on `ai.$NC_DOMAIN`, if installed. +It also covers [LocalAI](https://github.com/nextcloud/all-in-one/tree/main/community-containers/local-ai) by listening on `ai.$NC_DOMAIN`, if installed. +It also covers [azuracast](https://github.com/nextcloud/all-in-one/tree/main/community-containers/azuracast) by listening on `radio.$NC_DOMAIN`, if installed. ### Notes - This container is incompatible with the [npmplus](https://github.com/nextcloud/all-in-one/tree/main/community-containers/npmplus) community container. So make sure that you do not enable both at the same time! @@ -23,6 +24,7 @@ It also covers [LocalAI](https://github.com/nextcloud/all-in-one/tree/main/commu - If you want to use this with [seerr](https://github.com/nextcloud/all-in-one/tree/main/community-containers/jellyseerr), make sure that you point `requests.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for seerr. - If you want to use this with [nextcloud-exporter](https://github.com/nextcloud/all-in-one/tree/main/community-containers/nextcloud-exporter), make sure that you point `metrics.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for nextcloud-exporter. - If you want to use this with [local AI](https://github.com/nextcloud/all-in-one/tree/main/community-containers/local-ai), make sure that you point `ai.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for local AI. +- If you want to use this with [azuracast](https://github.com/nextcloud/all-in-one/tree/main/community-containers/azuracast), make sure that you point `radio.your-nc-domain.com` to your server using a cname record so that caddy can get a certificate automatically for azuracast. - After the container was started the first time, you should see a new `nextcloud-aio-caddy` folder and inside there an `allowed-countries.txt` file when you open the files app with the default `admin` user. In there you can adjust the allowed country codes for caddy by adding them to the first line, e.g. `IT FR` would allow access from italy and france. Private ip-ranges are always allowed. Additionally, in order to activate this config, you need to get an account at https://dev.maxmind.com/geoip/geolite2-free-geolocation-data and download the `GeoLite2-Country.mmdb` and upload it with this exact name into the `nextcloud-aio-caddy` folder. Afterwards restart all containers from the AIO interface and your new config should be active! - You can add your own Caddy configurations in the folder `nextcloud-aio-caddy/caddy-imports` in the files app of the default `admin` user. You need to create that folder manually. These will be imported on container startup. - You can alternatively add your own Caddy configurations in `/data/caddy-imports/` inside the Caddy container (`sudo docker exec -it nextcloud-aio-caddy bash`). These will be imported on container startup. **Please note:** If you do not have CLI access to the server use the previous option or run docker commands via a web session by using this community container: https://github.com/nextcloud/all-in-one/tree/main/community-containers/container-management diff --git a/community-containers/readme.md b/community-containers/readme.md index b0a3fe3e..e1616b5b 100644 --- a/community-containers/readme.md +++ b/community-containers/readme.md @@ -40,6 +40,7 @@ flowchart TD DLNA(["📡 DLNA\nMedia Streaming"]):::community MEMTR(["📸 Memories\nVideo Transcoder"]):::community MKV(["💿 MakeMKV\nBlu-ray / DVD rip"]):::community + AZURA(["📻 AzuraCast\nRadio Station Server"]):::community end subgraph COMM_MONITOR["📊 Monitoring & Infra"]