15 KiB
Public installation and release guide
Magent runs as one non-root Linux container containing the Python API and the Next.js frontend. Connect your own media services in the setup wizard; no pre-existing Magent account or database is required. Optional integrations may be skipped. Media files remain in your existing media services.
The lightweight Dockerfile builds the frontend separately and copies only its standalone runtime, static assets and public files into the final image. Build tools, the full development dependency tree and package-manager caches are not runtime requirements. The image still needs both Python and Node to serve the API and frontend; it is not a static website.
Both build and runtime stages use Alpine Linux, so native dependencies are built
for its musl runtime rather than copied from an incompatible glibc image.
The non-root UID/GID and /app/data layout are unchanged. Existing installations
do not need new databases, replacement keys or new data volumes for this change.
Magent's own source code is licensed under the MIT License. Bundled dependencies retain their own licenses; Magent's license does not relicense third-party software or grant rights to third-party branding.
Fresh installation
For the simplest Portainer installation, use the image-only root
compose.yml and follow the Portainer guide.
That fresh-install path pulls rephl3xnz/magent:latest from Docker Hub with no
environment inputs, automatically persists its private keys and requires no
Dockerfile or .env. Confirm the browser-facing application URL in the
token-authorized first-administrator wizard; matching CORS and cookie security
follow the saved URL automatically. Managed SQLite stays at
/app/data/magent.db, and API documentation stays disabled.
The managed-install image is published on Docker Hub. Repository changes alone
do not update an existing deployment: explicitly pull the image when upgrading,
retaining the same persistent volume. latest is mutable, so record the resolved
digest before an upgrade; older cached images may lack this setup workflow.
The Compose runtime-security block stays enabled and must be left unchanged.
See the complete environment reference for all supported
variables and the difference between managed, manual and tooling controls.
Advanced/manual secrets
The procedure below remains supported for operators who manage their own
deployment keys. It uses docker-compose.hub.yml, not the zero-input root
compose.yml; its required environment inputs are specific to this manual path.
Prerequisites: Docker Engine or Docker Desktop running Linux containers, Docker Compose v2, and an image release published for your host's architecture. Use the Compose and environment examples from the same release as the image.
-
Put
docker-compose.hub.ymland a copy of.env.examplenamed.envin a private deployment directory. Keep the directory and Compose project name stable: the project owns the persistent named volume. On Linux restrict.envto the deployment account, for examplechmod 600 .env; on Windows restrict its file permissions. Do not commit it, paste it into support reports or expose it through a web server. -
Set
MAGENT_IMAGEto the release's published immutable tag, for examplerephl3xnz/magent:prod-<actual-commit>, or its publishedrephl3xnz/magent@sha256:<actual-digest>. Replace the angle-bracket placeholders. There is deliberately no implicitlatestfallback. Confirm the selected release contains the setup/backup features before following this guide. -
Generate three independent values. Run these on a trusted machine; the commands print secrets, so do not share their output or put it in CI logs:
# JWT_SECRET python -c "import secrets; print(secrets.token_urlsafe(48))" # SETUP_TOKEN (not the JWT secret) python -c "import secrets; print(secrets.token_urlsafe(48))" # SETTINGS_ENCRYPTION_KEY (Fernet-compatible, using only Python's standard library) python -c "import base64, secrets; print(base64.urlsafe_b64encode(secrets.token_bytes(32)).decode())"Put each value in its matching
.envfield. LeaveADMIN_PASSWORDblank to create the administrator through the wizard. There is no shared default administrator password. Save the signing and encryption keys in a separate secure backup; generating replacement keys is not an upgrade step. -
For a local trial, keep
MAGENT_BIND_ADDRESS=127.0.0.1,MAGENT_HTTP_PORT=3000, the localhost URLs andAUTH_COOKIE_SECURE=false. For internet access, configure HTTPS as described below before inviting users. If changing the local port, update both browser-facing URLs too. -
Validate without printing expanded secrets, pull and start:
docker compose -p magent -f docker-compose.hub.yml config --quiet docker compose -p magent -f docker-compose.hub.yml pull magent docker compose -p magent -f docker-compose.hub.yml up -d --no-build magent docker compose -p magent -f docker-compose.hub.yml ps -
Open
http://localhost:3000on the Docker host (or your configured HTTPS address). The fresh database opens/setup. Enter the setup token, create your administrator, connect the apps you use, review preferences and finish. App URLs must be reachable from the container;localhostmeans Magent itself, not another container or the Docker host. Use your internal DNS, reachable LAN addresses or service names on an explicitly shared Docker network. -
Remove
SETUP_TOKENfrom.envand recreate only Magent using the sameup -d --no-build magentcommand. Setup progress and accounts remain in the volume. Make and test a backup before relying on the installation.
The template creates a project-scoped named volume at /app/data. The image's
data directory is prepared for UID/GID 1000:1000, avoiding the fresh root-owned
bind-directory problem. The container runs with a read-only root filesystem,
dropped capabilities and private temporary writable areas. The backend's port
8000 is not published: browser API calls use /api on the frontend port.
Do not run docker compose down --volumes unless you intend to erase the data.
HTTPS, public URLs and reverse proxies
For the managed Portainer path, visit the intended HTTPS address and confirm it in first-administrator setup. Later application URL changes belong in admin configuration. CORS and Secure cookies follow the saved URL; no environment values are required. Setup does not provision DNS, certificates or a proxy.
For the advanced/manual path, set these deployment values to your own origin, without a path or trailing slash:
CORS_ALLOW_ORIGIN=https://magent.example.com
MAGENT_APPLICATION_URL=https://magent.example.com
AUTH_COOKIE_SECURE=true
AUTH_COOKIE_SAMESITE=strict
The supplied image already routes browser /api/* calls to its internal API.
Do not expose port 8000, set a public API hostname or override the internal
backend URL for this combined-image deployment. Runtime environment changes do
not rebuild the frontend's compiled routing configuration.
With a reverse proxy running directly on the same host, use a loopback
bind and route the whole hostname, including /api, to 127.0.0.1:3000 (or your
chosen host port). The manual template defaults to loopback; in the root
Portainer template deliberately change its port mapping to 127.0.0.1:3000:3000
for this topology. For example, a host-running Caddy instance can use:
magent.example.com {
reverse_proxy 127.0.0.1:3000
}
For a containerized proxy, loopback inside that proxy is not the Docker host.
Attach the proxy and Magent to an intentionally shared Docker network and proxy
to magent:3000, or configure a reachable host address explicitly. If the proxy
is on another machine, bind the frontend host port to the Docker host's private
interface address and restrict access with a firewall to the trusted proxy. In
the root Portainer template edit the port mapping directly; the manual Hub
template instead supports MAGENT_BIND_ADDRESS.
Avoid exposing all interfaces merely to work around routing.
Provide valid TLS, suitable DNS and upload limits of at least 34 MiB for backup
restore. Do not cache login, setup, authenticated pages or API responses at the
proxy/CDN. Keep the exact public origin configured: the request-origin guard
does not trust arbitrary Host or forwarded headers. Keep API_DOCS_ENABLED=false
for public service. TLS terminates at your proxy, not inside this image.
Existing installations and upgrades
Do not replace an existing deployment with the fresh named-volume template.
Keep its existing project name, mount, database path, environment, signing key
and encryption key. Switching from ./data:/app/data to a new named volume makes
an existing installation look empty; it does not migrate data. Never complete
fresh setup to fix a missing mount.
For existing Linux bind mounts, confirm the exact intended data directory and
its files are writable by UID/GID 1000:1000. Back up first and correct only that
application directory if needed; do not recursively change an entire shared
stack, host directory or filesystem. Do not work around permissions by running
Magent as root. Custom UID/GID images require matching ownership.
Before upgrading:
- Save the old image tag and digest, Compose definition and protected environment/key backup. Create a consistent data backup and verify recovery.
- Read the target release's migration notes and select its immutable image. Pull it before interrupting service. Validate the actual saved deployment definition, including a Portainer stack's saved environment if used; editing a separate host Compose file does not update Portainer's copy.
- Recreate only Magent, retaining the original data mount and secrets. For
this template use
docker compose -p magent -f docker-compose.hub.yml up -d --no-deps --no-build magent. Use your actual project/file for other stacks. - Verify health, real local-account login, any enabled Jellyfin login, requests, app connections and invite behaviour. Do not trigger imports, notifications or destructive repair actions merely as a smoke test.
The zero-input Portainer template deliberately uses latest. On that path,
review the new release and pull its updated image when updating the existing
stack; restarting alone leaves the current image in use. Save the previous
digest because latest can move. Operators preferring controlled releases may
replace its literal image: value with a published immutable tag/digest without
changing the volume or generated keys.
For rollback, select the recorded image and recreate only Magent. Database migrations may prevent older versions from reading newer data: follow the release's compatibility notes and restore the matching backup if required. Restoring old data discards changes since that backup. Never restore a whole shared stack file over unrelated service changes.
Backups and recovery
For managed Portainer installations, retain bootstrap-secrets.json alongside
the database in consistent offline volume backups; the generated encryption key
is essential to recovering a raw database copy. It is deliberately excluded
from portable encrypted application exports. See Portainer persistence.
See installation and recovery for the encrypted admin backup/export flow and its size limits. It supports configuration, database and optional artwork cache. The backup passphrase cannot be recovered. Keep it separately and test a restore to a disposable instance of the same version.
For an offline volume backup, stop only Magent and snapshot/copy its complete
data volume, including SQLite journal/WAL sidecars. Start it again after the
consistent copy completes. Keep .env and the original encryption/signing keys
separately protected: encrypted settings in a raw database copy cannot be
recovered without the original encryption key (or original signing key for
older installations that derived their encryption key from it). The portable
encrypted application backup re-encrypts settings for its destination instead;
these are different recovery procedures.
Managed portable restore keeps the destination's confirmed application URL as
well as its signing/encryption keys. It does not replace the destination's
trusted origin with the source backup's URL; review integration addresses and
sign in using the destination URL after recovery.
Never rotate keys, replace the database or delete volumes as a response to an unhealthy container. Inspect health/log errors without posting credentials.
Public release gates
The release branch is a source snapshot, not a published image. Build and verify the exact commit before publishing Docker Hub tags.
This guide and the lightweight Dockerfile do not by themselves certify a
release. Before publishing a new immutable tag or moving latest:
- Build from the reviewed release commit with the root Dockerfile and its pinned
base digests. Do not send
.env, live data, local caches or development credentials in the build context. Record source revision, final image digest, compressed download size and unpacked image size separately. - Run backend and frontend checks, the production build and a container smoke test using the read-only Compose settings, a fresh named volume and non-root user. Confirm setup survives recreation, login works and the UI hydrates without CSP errors. Test backup/restore and an upgrade against a disposable copy, preserving its keys; never use live accounts/data for destructive tests.
- Check same-origin POST protection: empty-form requests to both
/api/auth/loginand/api/auth/jellyfin/loginwith the configured origin must reach validation (422); an unrelated origin must be rejected (403). These are necessary checks, not substitutes for a successful authenticated login. - Inspect the final image for development packages, build caches, unexpected credentials, unnecessary privileged execution and known dependency/base-image vulnerabilities. Review dependency notices and licensing before redistribution.
- Declare only architectures actually built and smoke-tested. A Linux/amd64 test is not an ARM64 test; an amd64 image running under emulation is not native ARM64 validation. Do not advertise a multi-architecture release until its manifest and each advertised platform have been verified. Docker Desktop runs the Linux image; this is not a native Windows-container or macOS build.
- Publish migration/rollback notes, supported image tags/digests and a support and private security-reporting route. Include the MIT license and required dependency notices, and confirm rights to any bundled branding assets. Publish only with the release owner's approval; building locally does not publish or deploy an image.