mirror of
https://github.com/HabiRabbu/Musicseerr
synced 2026-04-21 13:37:27 +00:00
Unraid/Nas Entrypoint.sh hardening + unraid xml template (#4)
* Unraid/Nas Entrypoint.sh hardening + unraid xml template * further entrypoint.sh hardening
This commit is contained in:
parent
eed1ce700d
commit
c141b9fcdf
4 changed files with 94 additions and 9 deletions
|
|
@ -180,6 +180,8 @@ MusicSeerr stores its config in `config/config.json` inside the mapped config vo
|
|||
|
||||
Run `id` on your host to find your PUID and PGID values.
|
||||
|
||||
> **Unraid / NAS users:** Unraid defaults to `nobody:users` (PUID=99, PGID=100). If you see `chown: Operation not permitted` at startup, your volume mount is on a filesystem that rejects ownership changes (FUSE/shfs, NFS, CIFS). The container skips `chown` when the directories and their contents are already writable, so this is usually fine as long as the host paths are owned by the correct UID:GID.
|
||||
|
||||
### In-App Settings
|
||||
|
||||
| Setting | Location |
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ services:
|
|||
environment:
|
||||
- PUID=1000 # User ID — run `id` on your host to find yours
|
||||
- PGID=1000 # Group ID — run `id` on your host to find yours
|
||||
# Unraid: use 99/100 (nobody:users) unless you changed Unraid's defaults.
|
||||
# If using Docker --user, PUID/PGID are ignored (user mapping is external).
|
||||
- PORT=8688 # Internal port (must match the right side of "ports" below)
|
||||
- TZ=Etc/UTC # Timezone — e.g. America/New_York, Europe/London
|
||||
ports:
|
||||
|
|
|
|||
|
|
@ -1,23 +1,77 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
umask 027
|
||||
|
||||
PUID=${PUID:-1000}
|
||||
PGID=${PGID:-1000}
|
||||
|
||||
groupmod -o -g "$PGID" musicseerr 2>/dev/null || true
|
||||
usermod -o -u "$PUID" musicseerr 2>/dev/null || true
|
||||
case "$PUID" in ''|*[!0-9]*) echo "[init] FATAL: PUID='$PUID' is not a valid numeric UID."; exit 1;; esac
|
||||
case "$PGID" in ''|*[!0-9]*) echo "[init] FATAL: PGID='$PGID' is not a valid numeric GID."; exit 1;; esac
|
||||
|
||||
check_writable() {
|
||||
_dir="$1"
|
||||
_identity="$2"
|
||||
_probe="$_dir/.musicseerr_write_test_$$"
|
||||
if [ -n "$_identity" ]; then
|
||||
gosu "$_identity" touch "$_probe" 2>/dev/null; _rc=$?
|
||||
gosu "$_identity" rm -f "$_probe" 2>/dev/null
|
||||
else
|
||||
touch "$_probe" 2>/dev/null; _rc=$?
|
||||
rm -f "$_probe" 2>/dev/null
|
||||
fi
|
||||
return "$_rc"
|
||||
}
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "[init] Running as uid=$(id -u) gid=$(id -g) (non-root); skipping user/group setup."
|
||||
for dir in /app/cache /app/config; do
|
||||
mkdir -p "$dir" 2>/dev/null || true
|
||||
if ! check_writable "$dir"; then
|
||||
echo "[init] FATAL: $dir is not writable by uid=$(id -u)."
|
||||
echo "[init] Ensure the host directory is owned by this UID/GID."
|
||||
echo "[init] Run: chown $(id -u):$(id -g) <host-path>"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
if ! groupmod -o -g "$PGID" musicseerr 2>/dev/null; then
|
||||
echo "[init] WARNING: Could not set musicseerr group to GID=$PGID."
|
||||
fi
|
||||
if ! usermod -o -u "$PUID" musicseerr 2>/dev/null; then
|
||||
echo "[init] WARNING: Could not set musicseerr user to UID=$PUID."
|
||||
fi
|
||||
|
||||
TARGET_UID=$(id -u musicseerr)
|
||||
TARGET_GID=$(id -g musicseerr)
|
||||
echo "[init] Runtime user: musicseerr (uid=$TARGET_UID gid=$TARGET_GID)"
|
||||
|
||||
if [ "$TARGET_UID" != "$PUID" ]; then
|
||||
echo "[init] WARNING: Requested PUID=$PUID but running as uid=$TARGET_UID (usermod may have failed)."
|
||||
fi
|
||||
if [ "$TARGET_GID" != "$PGID" ]; then
|
||||
echo "[init] WARNING: Requested PGID=$PGID but running as gid=$TARGET_GID (groupmod may have failed)."
|
||||
fi
|
||||
|
||||
# Only chown directories whose top-level ownership differs from the target.
|
||||
# Nested mismatches from manual edits require a rebuild or manual chown.
|
||||
for dir in /app/cache /app/config; do
|
||||
if [ -d "$dir" ]; then
|
||||
CURRENT=$(stat -c '%u:%g' "$dir")
|
||||
if [ "$CURRENT" != "$TARGET_UID:$TARGET_GID" ]; then
|
||||
chown -R musicseerr:musicseerr "$dir"
|
||||
fi
|
||||
mkdir -p "$dir" 2>/dev/null || true
|
||||
|
||||
if check_writable "$dir" "$TARGET_UID:$TARGET_GID"; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if chown musicseerr:musicseerr "$dir" 2>/dev/null; then
|
||||
echo "[init] Adjusted ownership of $dir - verifying write access."
|
||||
else
|
||||
echo "[init] WARNING: Could not chown $dir (mount may not support ownership changes)."
|
||||
fi
|
||||
|
||||
if ! check_writable "$dir" "$TARGET_UID:$TARGET_GID"; then
|
||||
echo "[init] FATAL: $dir is not writable by uid=$TARGET_UID gid=$TARGET_GID."
|
||||
echo "[init] Common causes: FUSE/shfs (Unraid), NFS root_squash, CIFS/SMB, dropped CAP_CHOWN."
|
||||
echo "[init] Fix: ensure the host directory is writable by uid=$TARGET_UID gid=$TARGET_GID."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
|
|
|
|||
27
templates/musicseerr.xml
Normal file
27
templates/musicseerr.xml
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Container version="2">
|
||||
<Name>musicseerr</Name>
|
||||
<Repository>ghcr.io/habirabbu/musicseerr:latest</Repository>
|
||||
<Registry>https://github.com/habirabbu/musicseerr/pkgs/container/musicseerr</Registry>
|
||||
<Network>bridge</Network>
|
||||
<Privileged>false</Privileged>
|
||||
<Support>https://github.com/HabiRabbu/Musicseerr/issues</Support>
|
||||
<Project>https://github.com/HabiRabbu/Musicseerr</Project>
|
||||
<Overview>MusicSeerr is a self-hosted music request and discovery app built around Lidarr. Search the full MusicBrainz catalogue, request albums, stream music from Jellyfin or Navidrome, discover new music based on your listening history, and scrobble to ListenBrainz and Last.fm. Requires a running Lidarr instance.</Overview>
|
||||
<Category>MediaApp:Music</Category>
|
||||
<WebUI>http://[IP]:[PORT:8688]</WebUI>
|
||||
<TemplateURL>https://raw.githubusercontent.com/HabiRabbu/Musicseerr/main/templates/musicseerr.xml</TemplateURL>
|
||||
<Icon>https://raw.githubusercontent.com/HabiRabbu/Musicseerr/main/Images/logo_icon.png</Icon>
|
||||
<Requires>A running Lidarr instance with an API key. Lidarr nightly build is recommended.</Requires>
|
||||
<ExtraSearchTerms>lidarr music request scrobble listenbrainz lastfm jellyfin navidrome</ExtraSearchTerms>
|
||||
<Screenshot>https://raw.githubusercontent.com/HabiRabbu/Musicseerr/main/Images/HomePage.png</Screenshot>
|
||||
<Screenshot>https://raw.githubusercontent.com/HabiRabbu/Musicseerr/main/Images/ArtistPage.png</Screenshot>
|
||||
<Screenshot>https://raw.githubusercontent.com/HabiRabbu/Musicseerr/main/Images/DiscoverPage.png</Screenshot>
|
||||
<Config Name="WebUI Port" Target="8688" Default="8688" Mode="tcp" Description="Port the MusicSeerr web interface listens on." Type="Port" Display="always" Required="true" Mask="false">8688</Config>
|
||||
<Config Name="Config" Target="/app/config" Default="/mnt/user/appdata/musicseerr/config" Mode="rw" Description="Persistent application configuration and database." Type="Path" Display="always" Required="true" Mask="false">/mnt/user/appdata/musicseerr/config</Config>
|
||||
<Config Name="Cache" Target="/app/cache" Default="/mnt/user/appdata/musicseerr/cache" Mode="rw" Description="Cover art and metadata cache." Type="Path" Display="always" Required="true" Mask="false">/mnt/user/appdata/musicseerr/cache</Config>
|
||||
<Config Name="Music Library" Target="/music" Default="" Mode="ro" Description="Optional: mount your music library root for local file playback. Must match the root folder Lidarr uses and the Music Directory Path in MusicSeerr Settings > Local Files." Type="Path" Display="advanced" Required="false" Mask="false"></Config>
|
||||
<Config Name="PUID" Target="PUID" Default="99" Mode="" Description="User ID for file permissions inside the container. Run 'id' on your Unraid terminal to find your value." Type="Variable" Display="advanced" Required="false" Mask="false">99</Config>
|
||||
<Config Name="PGID" Target="PGID" Default="100" Mode="" Description="Group ID for file permissions inside the container. Run 'id' on your Unraid terminal to find your value." Type="Variable" Display="advanced" Required="false" Mask="false">100</Config>
|
||||
<Config Name="Timezone" Target="TZ" Default="Europe/London" Mode="" Description="Your timezone. Examples: America/New_York, Europe/Berlin, Asia/Tokyo." Type="Variable" Display="always" Required="false" Mask="false">Europe/London</Config>
|
||||
</Container>
|
||||
Loading…
Reference in a new issue