Portainer setup guide

Two paths first.
Everything else explained.

Deploy the supplied stack in minutes, then understand the storage, streaming, security, and remote-access settings when you need them.

Quick start

Change two paths. Deploy the stack.

The supplied stack already contains the public image and safe defaults. For a normal installation, the only required edits are the two host-side folder paths.

Server data/srv/needle-web/data

Database, backups, artwork, logs, and generated streaming files.

Your music/media/music

The folder that contains the music After2AM Audio Server should index.

  1. Download the stack.Save the supplied YAML or paste it into Portainer’s stack web editor.
  2. Name the stack.Use needle-web, or another name you will recognize.
  3. Change the two paths.Edit only the left side of the two volume mappings for your first deployment.
  4. Deploy and open it.Deploy the stack, then visit http://<server-address>:2104.
  5. Finish setup.Create the first account, confirm the library folder, and start the initial scan.
Keep this private.

Port 2104 is for your local network. Never forward it—or container port 3000—directly from the router.

Storage

Your two folders

Docker sees the path on the right; your server sees the path on the left. Keep the container paths unchanged unless you are deliberately building a more advanced layout.

volumes:
  # Change the host-side paths on the left.
  - /srv/needle-web/data:/app/data
  - /media/music:/music
Persistent data

/app/data

Must survive container replacement. It holds the account, library database, settings, backups, artwork cache, Managed HTTPS state, and streaming derivatives.

Music library

/music

Mounted writable by default so supported tag edits can be saved to the files. Originals are not replaced when streaming copies are generated.

Networking

Three ports, three different jobs

Ports used by the Portainer stack
PortPurposeWhat to do
2104Default host port for direct LAN access.Open this from trusted devices at home. You may change the host side of the mapping.
3000Internal HTTP port used by the container.Leave it unchanged and never forward it from the router.
8443Dormant Managed HTTPS listener.Leave it alone unless enabling Managed HTTPS or resolving a host-port conflict.
ports:
  - "2104:3000/tcp"
  - "${NEEDLE_MANAGED_HTTPS_PORT:-8443}:${NEEDLE_MANAGED_HTTPS_PORT:-8443}/tcp"

The first number is the port on your Docker host. The second is the port inside the container. Changing 2104:3000 to 3001:3000 moves the local address to port 3001 without changing the server inside the container.

Reference

Every option in the supplied YAML

The defaults are intentional. Settings marked “leave” normally need no attention; they are documented here so the file is understandable rather than mysterious.

Container settings

Docker service options
SettingSupplied valueMeaning
services: needle-webneedle-webThe Compose service name used by Portainer.
imagedavidrelich/needle-web:latestThe public Docker image Portainer pulls when the stack is deployed or updated.
container_nameneedle-webA predictable container name for Portainer, logs, and maintenance.
restartunless-stoppedRestarts the server after a crash or host reboot unless you deliberately stopped it.
ports2104 and 8443Publishes the LAN server port and the dormant Managed HTTPS listener described above.
volumes/app/data and /musicConnects persistent server data and your music library to the container.

Core server settings

Core server environment options
OptionDefaultMeaning
PORT3000Internal server port. Leave unchanged.
NEEDLE_LIBRARY_ROOTS/musicOne or more in-container folders to index. Separate multiple roots with commas.
NEEDLE_WRITE_BACK_ENABLEDtrueAllows supported Rating, Tags, BPM, and album Genre edits to be written to compatible files.
NEEDLE_LOG_LEVELinfoNormal operational logging. Change only while diagnosing a problem.

Authentication and request boundaries

Authentication and request environment options
OptionDefaultMeaning
NEEDLE_SECURE_COOKIESautoUses secure cookies over HTTPS while preserving direct LAN login over HTTP. Recommended for the supplied stack.
NEEDLE_TRUSTED_PROXIESblankExact proxy IP addresses or narrow CIDRs. Leave blank unless the backend is private behind a configured external proxy.
NEEDLE_ALLOWED_HOSTSblankAdditional public or proxy hostnames. Normal IP, localhost, .local, and .home.arpa access needs no entry.
NEEDLE_ALLOWED_ORIGINSblankExtra origins permitted for browser mutations. Same-origin installations leave this blank.
NEEDLE_SETUP_TOKENblankOptional one-time secret for advanced initial setup through an existing proxy. Direct LAN setup does not need it.
NEEDLE_AUTH_JSON_BODY_LIMIT16kbMaximum setup and login request size. Leave unchanged.
NEEDLE_DEFAULT_JSON_BODY_LIMIT256kbMaximum ordinary authenticated mutation size. Leave unchanged.
NEEDLE_MEDIUM_JSON_BODY_LIMIT2mbLimit for playlists, playback state, Collection items, and desktop metadata payloads.
NEEDLE_ARTIST_IMAGE_JSON_BODY_LIMIT17mbAllows bounded manual artist-image uploads. Decoded images are capped separately.
NEEDLE_JSON_BODY_LIMIT50mbLimit for authenticated desktop-state bulk imports. Leave unchanged.

Streaming files

Streaming derivative environment options
OptionDefaultMeaning
NEEDLE_STREAMING_DERIVATIVES_ENABLEDtrueGenerates AAC-LC copies for predictable remote and mobile streaming without transcoding during playback.
NEEDLE_STREAMING_DERIVATIVE_DIR/app/data/streaming-cachePersistent location for generated streaming files. Leave inside /app/data.
NEEDLE_STREAMING_LOUDNESS_NORMALIZATIONtrueMeasures source loudness and applies controlled gain to generated copies. Originals remain untouched.
NEEDLE_STREAMING_LOUDNESS_MODEalbumPreserves the relative dynamics between tracks on the same album.
NEEDLE_STREAMING_TARGET_LUFS-16Target loudness baked into generated streaming copies.
NEEDLE_STREAMING_TRUE_PEAK_DB-1.5Peak-protection ceiling used while normalizing streaming copies.
NEEDLE_DERIVATIVE_CONCURRENCY2Maximum concurrent FFmpeg jobs. Lower it on resource-constrained hardware.
NEEDLE_DERIVATIVE_MIN_FREE_GB10Stops generation before the target filesystem would fall below this free-space reserve.
NEEDLE_DERIVATIVE_MIN_FREE_PERCENT10Adds a percentage-based reserve for shared or system disks.

Managed HTTPS helper

Managed HTTPS environment options
OptionDefaultMeaning
NEEDLE_MANAGED_CADDY_BIN/usr/bin/caddyBundled Caddy executable. Leave unchanged.
NEEDLE_MANAGED_CADDY_DIR/app/data/managed-caddyPersistent certificates, configuration, and logs.
NEEDLE_MANAGED_CADDY_RUNTIME_DIR/tmp/needle-managed-caddyTemporary runtime state inside the container.
NEEDLE_MANAGED_HTTPS_PORT8443Local listener targeted by WAN TCP 443 only after Managed HTTPS is enabled.

Variations

Three common changes

Make the music library read-only

Change both the write-back setting and the volume mount so the intent is explicit.

- NEEDLE_WRITE_BACK_ENABLED=false

volumes:
  - /media/music:/music:ro

Use another LAN port

Change only the host side. This example moves the local address to http://<server-address>:3001.

ports:
  - "3001:3000/tcp"

Use several mounted music folders

Mount each host folder under a distinct container path, then list those container paths as comma-separated roots.

environment:
  - NEEDLE_LIBRARY_ROOTS=/music/main,/music/vinyl

volumes:
  - /media/music:/music/main
  - /media/vinyl-rips:/music/vinyl

Remote access

Local first. Public only by choice.

Deploying the stack does not expose the library to the Internet. The Caddy binary and port mapping remain dormant until an authenticated user explicitly enables Managed HTTPS in After2AM Audio Server Settings.

Never expose the backend.

Do not router-forward host port 2104, container port 3000, TCP 80, or UDP 443. Managed HTTPS needs only WAN TCP 443 forwarded to the configured local managed-HTTPS port.

Managed HTTPS

  1. Complete first-account setup over the local network.
  2. Prepare a real domain, a direct DNS record, a public ISP address, and a stable LAN address for the Docker host.
  3. Forward WAN TCP 443 to host TCP 8443, unless you deliberately changed the managed port.
  4. Open Settings → Remote access → Managed HTTPS and complete the guided setup.
  5. Run the built-in checks, then test from a genuinely external connection.

If the ISP uses CGNAT, ordinary inbound forwarding will not work. Request a public address or use a suitable VPN or tunnel instead.

Existing HTTPS proxy

This is an advanced alternative. Keep the backend private, configure only the exact immediate proxy address in NEEDLE_TRUSTED_PROXIES, and add the public hostname to NEEDLE_ALLOWED_HOSTS. The proxy must preserve the original Host and overwrite incoming forwarding headers. The Remote access panel generates deployment-specific instructions.

Keep it healthy

Updates and troubleshooting

Preserve data

Keep /app/data

Updating or recreating the container is safe when the host data folder remains mounted to /app/data.

Empty library

Check the mount

Confirm the host music path exists, Docker can read it, and NEEDLE_LIBRARY_ROOTS names the container-side path.

Edits fail

Check both switches

Write-back needs a writable music mount and NEEDLE_WRITE_BACK_ENABLED=true.

Login loops on HTTP

Use cookie mode auto

A forced secure cookie requires HTTPS. The supplied auto mode supports both direct LAN HTTP and configured HTTPS.

Streaming repair stops

Check free space

The data volume must be writable and remain above both configured free-space reserves.

Image will not pull

Check Docker Hub access

The host must be able to pull davidrelich/needle-web:latest before Portainer can deploy it.

Ready to deploy

Keep the defaults. Change your paths.

That is enough for a normal local installation. Return here only when you need a deliberate variation.