docs(install): cover Docker and native deployments

This commit is contained in:
Magent release tooling
2026-09-20 17:09:14 +12:00
parent 4aba89c063
commit 76b2b8d879
16 changed files with 1141 additions and 53 deletions
+1
View File
@@ -21,6 +21,7 @@ bootstrap-secrets.json
.magent-secrets-*
data/*
!data/branding/
backend/data/
*.tar
*.tar.gz
*.zip
+33 -15
View File
@@ -2,37 +2,54 @@
Self-hosted media requests, viewing stats and issue management for Jellyfin,
Seerr, Sonarr, Radarr and related services. Magent combines a Python/FastAPI API,
a Next.js frontend and SQLite in one non-root container.
a Next.js frontend and SQLite. Run the prebuilt non-root container or install
the Python and Node.js services directly—Portainer is optional.
## Install
Paste [compose.yml](compose.yml) into a Portainer **Docker Standalone** stack.
It uses `rephl3xnz/magent:latest`, persists data in a named volume and needs no
environment variables or Dockerfile on the user's machine.
Start with the [installation guide](docs/INSTALLATION.md) to choose a method:
| Method | Instructions |
| --- | --- |
| Docker Compose or `docker run` | [Docker installation](docs/DOCKER.md) |
| Portainer | [Single-file stack](docs/PORTAINER.md) |
| Linux without Docker | [Native install and systemd services](docs/NATIVE_INSTALL.md) |
| Windows/macOS/Linux foreground | [Source installation and development](docs/LOCAL_DEVELOPMENT.md) |
For a fresh **Docker Compose** install, download [compose.yml](compose.yml) into
its own deployment directory and run:
```sh
docker compose -f compose.yml -p magent pull
docker compose -f compose.yml -p magent up -d --wait --wait-timeout 120
docker compose -f compose.yml -p magent ps
docker compose -f compose.yml -p magent exec --user magent magent python -m app.container_bootstrap setup-token
```
Keep that directory/project name and its persistent volume unchanged for updates.
This uses `rephl3xnz/magent:latest` with no environment variables, local source
build or Dockerfile. Portainer users can paste the same file into a Docker
Standalone stack instead. Native users follow their separate guide for explicit
environment configuration and service management.
**Image availability:** the managed-install image is published on Docker Hub.
Only Linux/amd64 has been validated. `latest` is mutable; record the resolved
image digest before updating, or pin an immutable release tag.
1. Deploy the stack and wait for the container to become healthy.
2. In its console, select `/bin/ash` and user `magent`, then run:
```sh
python -m app.container_bootstrap setup-token
```
3. Open the Docker host's address on port 3000. Confirm the browser-facing URL
1. Wait for the container to become healthy and retrieve the token using the
command above (or the Portainer console instructions in its guide).
2. Open the Docker host's address on port 3000. Confirm the browser-facing URL
in setup and use the token to create the first administrator.
The **Get setup token** button shows the console instructions and lets you
copy the command; it never reveals the token to public visitors.
4. Connect your apps, choose preferences and finish setup. Optional apps can
3. Connect your apps, choose preferences and finish setup. Optional apps can
be skipped. Save an encrypted backup afterwards.
Keep the Compose security block unchanged. Database storage is fixed at
`/app/data/magent.db` and API docs are disabled in managed installs. CORS and
cookie security follow the confirmed URL. Use HTTPS before public access.
See [Portainer setup](docs/PORTAINER.md),
See [all installation methods](docs/INSTALLATION.md),
[all environment options](docs/ENVIRONMENT.md),
[backup and restore](docs/installation-and-recovery.md) and
[advanced installation/upgrades](docs/PUBLIC_RELEASE.md).
@@ -44,7 +61,7 @@ encryption keys; this fresh-install template is not an automatic migration.
The source tree contains everything needed to build the application:
```sh
docker compose -f compose.yml -f compose.build.yml up -d --build
docker compose -f compose.yml -f compose.build.yml -p magent up -d --build
```
For a disposable verification run, without touching an existing installation:
@@ -85,6 +102,7 @@ at live services or use production credentials.
- `backend/tests/` and frontend `*.test.*`: synthetic regression tests.
- `Dockerfile` and `docker/`: multi-stage build and process supervision.
- `compose.yml`: prebuilt-image install; `compose.build.yml`: source override.
- `deploy/native/`: example Linux service units and backend/frontend configuration.
Requests are cached from Seerr, joined to collector/download/library evidence,
normalised into a user-facing state and displayed by the frontend. App settings
+1 -1
View File
@@ -1,5 +1,5 @@
# Optional source build; retain compose.yml's storage and security defaults.
# docker compose -f compose.yml -f compose.build.yml up -d --build
# docker compose -f compose.yml -f compose.build.yml -p magent up -d --build
services:
magent:
image: magent:local
+3 -1
View File
@@ -1,4 +1,6 @@
# Fresh installs: paste this file into a Portainer Docker Standalone stack.
# Fresh installs: use Docker Compose CLI or a Portainer Docker Standalone stack.
# CLI: docker compose -f compose.yml -p magent up -d
# Instructions: docs/DOCKER.md or docs/PORTAINER.md.
# Configure the site address and connected apps in Magent's setup wizard.
# No Dockerfile, source checkout, .env file or shared default password is needed.
# Existing installations must keep their original data mount and keys.
+13
View File
@@ -0,0 +1,13 @@
# Copy to /etc/magent/backend.env, owned by root with mode 0600.
# Generate independent secrets; these placeholders must never be deployed.
JWT_SECRET=REPLACE_WITH_INDEPENDENT_RANDOM_TOKEN
SETTINGS_ENCRYPTION_KEY=REPLACE_WITH_FERNET_KEY
SETUP_TOKEN=REPLACE_WITH_ANOTHER_RANDOM_TOKEN
MAGENT_MANAGED_SECRETS=false
MAGENT_APPLICATION_URL=https://magent.example.com
CORS_ALLOW_ORIGIN=https://magent.example.com
AUTH_COOKIE_SECURE=true
API_DOCS_ENABLED=false
SQLITE_PATH=/var/lib/magent/data/magent.db
LOG_FILE=/var/lib/magent/data/magent.log
BRANDING_SOURCE=data
+26
View File
@@ -0,0 +1,26 @@
[Unit]
Description=Magent API
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=magent
Group=magent
WorkingDirectory=/var/lib/magent
EnvironmentFile=/etc/magent/backend.env
Environment=PYTHONDONTWRITEBYTECODE=1
Environment=PYTHONUNBUFFERED=1
ExecStart=/opt/magent/.venv/bin/python -m uvicorn app.main:app --app-dir /opt/magent/backend --host 127.0.0.1 --port 8000 --workers 1
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
UMask=0077
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/magent/data
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,8 @@
# Copy to /etc/magent/frontend.env. This file must not contain backend secrets.
NODE_ENV=production
NEXT_TELEMETRY_DISABLED=1
HOSTNAME=127.0.0.1
PORT=3000
NEXT_PUBLIC_API_BASE=/api
BACKEND_INTERNAL_URL=http://127.0.0.1:8000
MAGENT_APPLICATION_URL=https://magent.example.com
+25
View File
@@ -0,0 +1,25 @@
[Unit]
Description=Magent web frontend
Wants=network-online.target magent-backend.service
After=network-online.target magent-backend.service
[Service]
Type=simple
User=magent
Group=magent
WorkingDirectory=/opt/magent/frontend
EnvironmentFile=/etc/magent/frontend.env
# If command -v node reports another system-wide path, update this line.
ExecStart=/usr/bin/node /opt/magent/frontend/.next/standalone/server.js
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
UMask=0077
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/magent/frontend/.next/standalone/.next/cache
[Install]
WantedBy=multi-user.target
+418
View File
@@ -0,0 +1,418 @@
# Install Magent with Docker
For a fresh installation, Docker Compose runs the published
`rephl3xnz/magent:latest` image with persistent storage and the required runtime
security settings. Magent contains both its Python API and Next.js frontend;
you do not install Python, Node.js, a separate database, or your media apps as
part of this procedure. No Dockerfile, source checkout, `.env`, manually
generated keys, or default administrator password is needed.
This guide covers Compose CLI, direct `docker run`, and building from source.
For a graphical deployment, use [Portainer](PORTAINER.md). For installation
without containers, see [native installation](NATIVE_INSTALL.md).
Existing installations must keep their original data mount and keys; read
[existing installations](#existing-installations) before changing a deployment.
## Prerequisites
- A Docker daemon running **Linux containers**. Only `linux/amd64` has been
validated for Magent. ARM64, Raspberry Pi and Apple Silicon are not advertised
as supported targets; selecting amd64 emulation does not establish native
ARM64 compatibility.
- For Linux, install [Docker Engine for your distribution](https://docs.docker.com/engine/install/)
and the [Docker Compose plugin](https://docs.docker.com/compose/install/linux/).
Use the `docker compose` plugin commands shown here; the legacy
`docker-compose` executable is outside this guide. Follow Docker's
distribution-specific package instructions; installing only the CLI does
not provide a running daemon.
- On a supported Windows or macOS desktop, follow Docker's
[Windows installation guide](https://docs.docker.com/desktop/setup/install/windows-install/)
or [Mac installation guide](https://docs.docker.com/desktop/setup/install/mac-install/).
Start Docker Desktop and use its Linux-container engine. Check Docker's host
requirements and subscription terms. Docker Desktop is not supported on
Windows Server. The container stops being available when its VM/daemon or
host is shut down or asleep; plan that lifecycle before using a desktop as
an always-on server.
- A persistent Docker storage location with room for the image, database,
artwork cache and backups. Follow [Docker Desktop backup and recovery](https://docs.docker.com/desktop/settings-and-maintenance/backup-and-restore/)
before resetting or uninstalling it; its volumes live in the Linux VM.
- A stable browser-facing address. Trusted-LAN HTTP can be used for initial
local setup; arrange DNS and an HTTPS reverse proxy before public access.
The host needs outbound access to the image registry and whichever optional
integrations you configure.
Check the selected daemon and Compose installation:
```sh
docker version
docker compose version
docker info --format '{{.OSType}}/{{.Architecture}}'
```
The daemon must report Linux, with an x86-64/amd64 architecture for the validated
image. On Linux, your account may need `sudo` for Docker commands. Access to the
Docker socket or `docker` group grants powerful host privileges; follow
[Docker's Linux post-installation guidance](https://docs.docker.com/engine/install/linux-postinstall/).
The multi-line shell examples below use Bash, as available on Linux, macOS or
an integrated WSL terminal. A separate PowerShell download example is included;
the single-line Docker commands also work in PowerShell. Magent remains a Linux
container in either case, not a native Windows-container or macOS application.
## Docker Compose
### 1. Save the deployment file
Create a new directory for this installation and save the release branch's
[raw compose.yml](https://git.amslabs.net/Rephl3x/Magent/raw/branch/release/compose.yml)
there. Keep your customized copy for future operations instead of overwriting
it when updating. You need only this file for the prebuilt image.
Linux, macOS or WSL:
```sh
mkdir magent-install
cd magent-install
curl --fail --location --output compose.yml https://git.amslabs.net/Rephl3x/Magent/raw/branch/release/compose.yml
```
PowerShell:
```powershell
New-Item -ItemType Directory -Path magent-install
Set-Location magent-install
Invoke-WebRequest -Uri 'https://git.amslabs.net/Rephl3x/Magent/raw/branch/release/compose.yml' -OutFile compose.yml
```
Alternatively, open the raw link in your browser and save the plain text as
`compose.yml`, not `compose.yml.txt`. It should contain a `services:` section
with `image: rephl3xnz/magent:latest`, not an HTML page. If your network requires
repository sign-in, download the raw file through your authenticated browser;
do not insert account credentials into a shared shell command.
All examples explicitly select `-f compose.yml` and project `-p magent`.
Keep that project name stable: with the unchanged file, its volume is
`magent_magent-data`. Changing the project name can create a different, empty
volume; it does not move the database. If you choose another name, use it on
every subsequent command. Docker documents
[how project names select an installation](https://docs.docker.com/compose/how-tos/project-name/).
### 2. Review ports and start the container
The supplied `3000:3000` mapping publishes port 3000 on host interfaces for LAN
access. If that port is occupied, edit only the left side, for example
`3100:3000`, and use port 3100 in your browser. For a reverse proxy running
directly on the same host, use `127.0.0.1:3000:3000` to bind to loopback.
Keep the data mount and security block intact.
Validate the saved file, pull the image, and start it:
```sh
docker compose -f compose.yml -p magent config --quiet
docker compose -f compose.yml -p magent pull magent
docker compose -f compose.yml -p magent up -d --no-build magent
docker compose -f compose.yml -p magent ps
```
Wait until the container reports `healthy`; its first health check can take
several seconds. A detached start completing does not by itself mean the
application is ready. To inspect a startup problem:
```sh
docker compose -f compose.yml -p magent logs --tail 100 magent
```
Review logs privately and redact sensitive information before sharing them.
This deployment runs one Magent service and one SQLite database; do not scale
it to multiple replicas sharing the same volume.
### 3. Retrieve the setup token
Once the container is healthy, run this from your deployment directory:
```sh
docker compose -f compose.yml -p magent exec --user magent magent python -m app.container_bootstrap setup-token
```
The command displays the private token that Magent generated at first start.
It does not generate replacement keys, and it stops returning the token once
an administrator exists. Keep its output private: someone with the token and
access to an unclaimed installation can create its first administrator.
The setup page's **Get setup token** button provides console instructions and
copies the command. It does not expose the token through the public website.
When automatic clipboard access is unavailable, select and copy the command
manually. You do not need to open an interactive shell for the Compose command
above; if using a container console, select `/bin/ash` and user `magent`.
### 4. Complete the browser wizard
Open the Docker host's reachable address, for example
`http://192.168.1.50:3000`, or your configured HTTPS hostname. On the same
desktop as Docker, `http://localhost:3000` may be suitable for local-only use.
Choose the address your users will actually open before creating the account.
1. Confirm the **Public Magent URL** shown on `/setup`. It must match the
browser's origin: scheme, hostname and any non-default port, without a path,
query, credentials or fragment. To use another hostname, open Magent there
first.
2. Paste the setup token and create your administrator with a unique password
of at least 12 characters. There is no shared default login.
3. Connect and test the media apps you use, then select preferences and finish.
Optional integrations can be skipped. Background imports remain paused
until setup is completed.
4. Export an encrypted backup from **Settings → Advanced tools → Backup & restore**
and keep its passphrase separately.
Managed installs save the confirmed origin and derive matching CORS and cookie
security from it. Their database path is fixed at `/app/data/magent.db`, and
API documentation stays disabled. Do not add manual signing/encryption keys
or override these fixed managed settings to complete setup. Advanced legacy
environment configuration is documented separately in [ENVIRONMENT.md](ENVIRONMENT.md).
App connection addresses must be reachable from Magent's container. Inside a
container, `localhost` refers to that container. Use a reachable LAN/DNS address
or an intentionally shared Docker network for other services. Magent does not
need a Docker socket mount or access to your media files.
## Docker CLI without Compose
This is an alternative for a fresh installation managed without Compose.
Record the complete command for future recreation. The example uses container
`magent`, network `magent-run`, and a named volume `magent_magent-data`, matching
the data-volume name used by the `-p magent` Compose example. Do not run both
examples against that volume at once. The commands are not a migration between
Compose and manually managed containers; existing deployments must retain
their actual mounts and management method.
```sh
docker volume create magent_magent-data
docker network create magent-run
docker pull rephl3xnz/magent:latest
docker run --detach \
--name magent \
--network magent-run \
--publish 3000:3000 \
--mount type=volume,source=magent_magent-data,target=/app/data \
--restart unless-stopped \
--stop-timeout 30 \
--read-only \
--cap-drop ALL \
--security-opt no-new-privileges:true \
--init \
--tmpfs /tmp:rw,noexec,nosuid,size=64m,uid=1000,gid=1000 \
--tmpfs /app/frontend/.next/cache:rw,noexec,nosuid,size=128m,uid=1000,gid=1000 \
rephl3xnz/magent:latest
```
In PowerShell, use the same `docker run` arguments on one line, or replace each
Bash continuation backslash with PowerShell's backtick continuation character.
Do not paste the backslashes into PowerShell as separate commands.
The data mount, published port, restart policy, 30-second stop grace period,
read-only root, dropped capabilities, privilege restriction, init process and
two temporary mounts match the supplied Compose settings. The image already
selects the unprivileged `magent` user and includes its health check, so do not
override the user or entrypoint. Runtime flags are documented in
[Docker's run reference](https://docs.docker.com/reference/cli/docker/container/run/).
Check readiness and retrieve the token:
```sh
docker ps --filter name=magent
docker inspect --format '{{.State.Health.Status}}' magent
docker logs --tail 100 magent
docker exec --user magent magent python -m app.container_bootstrap setup-token
```
Then follow the same [browser wizard](#4-complete-the-browser-wizard).
For a different port or proxy topology, change `--publish` as described in
[ports and HTTPS](#ports-https-and-browser-security).
## Build the container from source
Use this path when you intentionally want to build the application yourself.
It requires the full source tree and Docker build support; the prebuilt-image
installation does not. Use a separate checkout directory:
```sh
git clone --branch release --single-branch https://git.amslabs.net/Rephl3x/Magent.git Magent-source
cd Magent-source
docker compose -f compose.yml -f compose.build.yml -p magent config --quiet
docker compose -f compose.yml -f compose.build.yml -p magent build magent
docker compose -f compose.yml -f compose.build.yml -p magent up -d --no-build magent
docker compose -f compose.yml -f compose.build.yml -p magent ps
```
For a reproducible build, check out the reviewed release commit before the
build command. [compose.build.yml](../compose.build.yml) changes the image to
`magent:local` and adds `build: .`; the storage and security settings still come
from root `compose.yml`. It uses the same managed first-install workflow and
needs no `.env`. Retrieve its token with:
```sh
docker compose -f compose.yml -f compose.build.yml -p magent exec --user magent magent python -m app.container_bootstrap setup-token
```
Use **both** `-f` arguments on subsequent source-build operations, including
restart, logs and upgrades. A command using only `compose.yml` would select the
Docker Hub image instead. Keep the project name and volume stable. Builds for
unvalidated architectures remain your own compatibility-testing responsibility.
## Ports, HTTPS and browser security
Only frontend port 3000 needs publishing. The combined image routes `/api/*`
internally; do not publish backend port 8000 or configure a second browser API
origin. Keep the whole application at the root of its hostname, including
`/api` and `/_next` paths.
For public access, configure DNS, a valid TLS certificate and an HTTPS reverse
proxy. TLS terminates at that proxy; Magent does not provision it. A proxy
running directly on the Docker host can forward to `127.0.0.1:3000` when Magent
is published on host loopback. A containerized proxy needs an explicitly shared
Docker network or reachable host interface: its own loopback is not the host.
See the [reverse-proxy examples](PUBLIC_RELEASE.md#https-public-urls-and-reverse-proxies).
The default LAN port mapping listens on host interfaces. Do not internet-forward
the plain-HTTP port. Confirm your firewall actually filters Docker-published
ports; Linux Docker forwarding can bypass ordinary `ufw` rules. Follow
[Docker's firewall documentation](https://docs.docker.com/engine/network/packet-filtering-firewalls/)
for the daemon and network in use.
Confirm the public HTTPS origin during setup, or change it deliberately in
administrator settings when moving addresses. Cookies and request-origin
checks must agree with the address open in the browser. After deliberately
changing the saved origin, restart Magent so its frontend also reloads the
origin-dependent security policy. For the Compose installation, use
`docker compose -f compose.yml -p magent restart magent`; for source builds,
include `-f compose.build.yml` as well. HTTPS also enables
browser features requiring a secure context. Do not resolve login failures by
disabling origin checks, using wildcard CORS, or weakening cookie protection.
Do not cache setup, login, authenticated pages or API responses at the proxy/CDN.
Preserve Magent's Content Security Policy and per-response script nonces;
mixing cached HTML with another response's CSP can leave the page unable to
run. Allow at least 34 MiB for the full backup-restore HTTP upload.
## Persistence and backups
With `-p magent`, root Compose creates `magent_magent-data` and mounts it at
`/app/data`. It contains the database, settings, cached artwork, branding and
private `bootstrap-secrets.json`. That file holds the generated deployment keys.
Keep it together with the raw database; deleting it does not reset a password
and can make encrypted settings unrecoverable. Docker host administrators can
access the volume, so protect the host and its backups.
Use the application's encrypted `.magent-backup` export for portable recovery,
and test restoring it to a disposable instance of the same version. The export
excludes deployment keys and re-encrypts settings for the destination's keys
when restored. Managed restore retains the destination's confirmed URL. See
[backup and restore](installation-and-recovery.md) for limits and the complete
procedure; the backup passphrase cannot be recovered.
For an offline snapshot or copy, stop only Magent, back up the entire volume
consistently, and start it again after the copy completes:
```sh
docker compose -f compose.yml -p magent stop magent
# Take and verify a protected snapshot/copy of the complete magent_magent-data volume.
docker compose -f compose.yml -p magent start magent
```
Keep SQLite sidecar files and original generated keys with that full-volume
copy. Copying only the live database file is not an equivalent backup. Preserve
your deployment file, chosen image digest, proxy configuration and backup
passphrase separately. For direct Docker use, the corresponding commands are
`docker stop --timeout 30 magent` and `docker start magent`.
## Pin an image, update, or roll back
`latest` is a moving tag. Before an update, export a backup, retain the deployment
definition and record the image actually running:
```sh
docker compose -f compose.yml -p magent images magent
```
Use the reported image ID in the next command, replacing `IMAGE_ID`:
```sh
docker image inspect IMAGE_ID --format '{{json .RepoDigests}}'
```
Record the complete `rephl3xnz/magent@sha256:...` reference, together with the
image ID. A locally built image may not have a repository digest; keep its
source commit and a retained image tag/archive. To pin a published image, edit
only `image:` in your saved Compose file to the recorded full digest reference
or a published release tag. A digest is immutable; an ordinary tag can move.
See [Docker's digest-pull documentation](https://docs.docker.com/reference/cli/docker/image/pull/).
After reviewing the target release's compatibility notes and selecting the
image in your saved file, update only Magent:
```sh
docker compose -f compose.yml -p magent config --quiet
docker compose -f compose.yml -p magent pull magent
docker compose -f compose.yml -p magent up -d --no-deps --no-build magent
docker compose -f compose.yml -p magent ps
docker compose -f compose.yml -p magent logs --tail 100 magent
```
An updated image causes Compose to recreate the service while retaining its
mounted volume. A plain restart does not pull or apply a newer image. Verify
health, sign-in, settings, enabled integrations and invites after the update.
Docker documents [recreation and volume preservation](https://docs.docker.com/reference/cli/docker/compose/up/).
For a direct `docker run` installation, first record its image ID and repository
digest, save the full run command and back up the volume. Pull the selected
replacement, stop and remove only the `magent` container, then repeat the saved
run command with that image and the **same named volume**. Do not remove the
volume or drop security flags during recreation. For source builds, back up,
select the reviewed source revision, and repeat the build/up commands with
both Compose files instead of pulling the Hub image.
For rollback, select the previously recorded image and recreate only Magent.
An older image may be unable to read data migrated by a newer version; restore
the matching pre-update backup if the release requires it. Restoring that
backup discards changes made since it was taken. Keep the current data backed
up before attempting recovery.
Never add `--volumes` or `-v` to a Compose `down` command during an update or
routine recovery: it removes declared named volumes. An ordinary `down` also
stops/removes the service and its network and is unnecessary for normal
updates. Avoid volume pruning and Docker Desktop data resets unless you intend
to erase their contents. See [Docker's down reference](https://docs.docker.com/reference/cli/docker/compose/down/).
## Troubleshooting
| Symptom | Check |
| --- | --- |
| `docker compose` is unavailable | Install the Compose plugin and confirm `docker compose version`. Start the selected Docker daemon/Desktop instance. |
| Cannot connect to the daemon or permission denied | Check `docker version`, the selected Docker context, and the deployment account's access. Do not expose an unauthenticated Docker API. |
| No matching image manifest or an executable-format error | Check Linux-container mode and CPU architecture. Only Linux/amd64 is validated; do not assume ARM64 support. |
| Port 3000 is already allocated | Identify the existing listener. Choose another host port such as `3100:3000` in your saved file and use that address in setup. |
| Browser cannot reach Magent | Check `ps`, health and logs, the Docker host's reachable IP, published port, and Docker-aware firewall rules. A loopback bind is reachable only from its host. |
| Fresh setup appears after an update | Stop and check the original project name and data mount. Do not create another administrator or replace generated keys to work around an empty/wrong volume. |
| Token command says the database is uninitialized | Wait for healthy status, then inspect startup logs if it remains unhealthy. Do not generate a second secrets file. |
| Token command says initial setup is no longer available | An administrator exists or setup is complete. Sign in with the established account; recreating the container does not reopen bootstrap. |
| Login rejects the origin or returns to sign-in | Use the exact saved origin, including scheme and port. Check HTTPS/proxy configuration and cookie handling. A domain, LAN IP and `localhost` are different origins. |
| Page stays blank or scripts are blocked by CSP | Inspect browser console/network errors. Remove unintended proxy/CDN HTML caching and conflicting security headers; preserve the application's CSP and nonces. Hard-refresh after correcting the proxy. |
| Copy command is unavailable over LAN HTTP | Use the selected command's manual-copy fallback, or configure HTTPS. Other secure-context browser features may also need HTTPS. |
| A service connection to `localhost` fails | Use an address reachable from the container, or an explicitly shared network with that service. |
| Read-only/permission errors | Keep both tmpfs mounts and the correct data volume. The image runs as UID/GID 1000:1000. For an existing bind mount, back up and correct only that verified application directory; do not run Magent privileged or as root. |
| A backup upload fails at the proxy | Allow at least 34 MiB for the multipart upload and consult the application backup limits. Do not post backups or passphrases in support logs. |
## Existing installations
The root template is for fresh managed installations. It does not migrate a
manual-secret deployment, change an existing bind mount into a named volume,
or replace established keys. Retain the original project, volume or bind mount,
database location, signing/encryption keys and environment settings. An empty
volume is a new installation, not evidence that old data was migrated.
Continue using your saved deployment definition or the advanced
[manual-secret guide](PUBLIC_RELEASE.md#advancedmanual-secrets) and
[docker-compose.hub.yml](../docker-compose.hub.yml) where appropriate. Review
the [upgrade and recovery guidance](PUBLIC_RELEASE.md#existing-installations-and-upgrades)
before changing storage or secret management. Never run two Magent instances
against the same SQLite volume.
+6 -3
View File
@@ -1,6 +1,6 @@
# Environment variable reference
The public [Portainer stack](../compose.yml) needs **no environment variables**.
The public [Docker Compose/Portainer stack](../compose.yml) needs **no environment variables**.
Its image supplies the runtime defaults; use the first-run setup wizard to set
the application URL, connect services and configure notifications. The normal
stack does not need a Dockerfile, source checkout or `.env` file.
@@ -8,6 +8,8 @@ stack does not need a Dockerfile, source checkout or `.env` file.
This reference also covers advanced/manual deployments, compatibility aliases,
image-build inputs and repository-only tooling. A variable being listed here
does **not** mean that it belongs in the public Compose file.
For non-container deployments, follow the explicit configuration steps in
[native Linux installation](NATIVE_INSTALL.md) or [foreground installation](LOCAL_DEVELOPMENT.md).
## Managed installation defaults and precedence
@@ -31,8 +33,9 @@ does **not** mean that it belongs in the public Compose file.
deployment controls, not ordinary editable settings. Container listener ports
are fixed by its process supervisor, not by application settings.
- For manual deployments, environment variables are read at process startup.
Restart/recreate after changing them. A `.env` file is loaded by the relevant
Compose template's `env_file`, not automatically discovered by the application.
Restart/recreate after changing them. Load the private file through the relevant
manual Compose template's `env_file`, native systemd `EnvironmentFile`, or
foreground Uvicorn `--env-file`; it is not automatically discovered by the application.
Keep manual credentials stable across upgrades and offline restores.
Defaults use JSON notation: `null` means unset, `""` means an empty string,
+146
View File
@@ -0,0 +1,146 @@
# Choose your installation method
Magent does not require Portainer. It runs either as one prebuilt Linux container
or as a Python API plus a Node.js frontend installed directly on your machine.
All methods use SQLite, the same setup wizard and the same backup/restore UI.
They do not install Jellyfin, Seerr, Sonarr or any of your other media services.
| Your situation | Guide | What you install/manage |
| --- | --- | --- |
| Docker Engine with a terminal | [Docker Compose](DOCKER.md#docker-compose) | Recommended container path; no source build or environment inputs |
| Docker without Compose | [Docker CLI](DOCKER.md#docker-cli-without-compose) | One `docker run` command, persistent named volume and explicit security flags |
| You already use Portainer | [Portainer](PORTAINER.md) | Paste `compose.yml` into a Docker Standalone stack |
| You want to build your own container | [Docker source build](DOCKER.md#build-the-container-from-source) | Git checkout, Docker and the source-build override |
| Linux server without Docker | [Native Linux](NATIVE_INSTALL.md) | Python 3.14, Node 24, private configuration and two systemd services |
| Local development or foreground use without Docker | [Linux/macOS/Windows](LOCAL_DEVELOPMENT.md) | Native dependencies and two terminal processes; no service-manager installation |
## Platform and support boundaries
- The published container has been built and smoke-tested for **Linux/amd64**.
Check the registry manifest before choosing another architecture. ARM64,
Raspberry Pi and Apple Silicon native-image support are not advertised;
amd64 emulation is not native ARM64 validation.
- Docker Desktop on Windows/macOS runs Linux containers in a Linux environment;
it is not a native Windows container or native macOS application. Enable Linux
containers. WSL2 can also host the Linux instructions when its prerequisites
are installed; systemd availability depends on that WSL installation.
- The native Linux systemd files are deployment examples, not an unattended OS
installer or a certification of every distribution. Install compatible Python,
Node and native dependencies using their maintainers' instructions. Native
foreground checks do not prove boot-time service operation on another OS.
- Windows/macOS foreground instructions are for local evaluation/development.
This repository does not ship Windows Service or launchd installers.
- Run **one backend process/worker and one writable SQLite instance**. Do not
share its database between replicas, combine old/new versions against the same
data, or put SQLite on network storage. Kubernetes/Swarm/HA deployments are not
supplied or validated by these single-instance examples.
## Before starting
Choose a stable browser URL, reserve the required ports, and decide where your
persistent data and off-host backups will live. Storage use depends on request
history and optional artwork caching; leave additional room for backup staging
and rollback copies. Source builds also need dependency/build space and more
memory than the running application. No universal RAM/disk minimum has been
benchmarked.
For public use, configure DNS and HTTPS before creating the administrator. On a
trusted LAN, HTTP can be used deliberately; do not forward its plain-HTTP port
directly to the internet. Container examples publish **3000**; the browser uses
`/api` on that same frontend address. The backend's **8000** port should not be
exposed publicly. Native production examples bind both services to loopback.
An app address entered into Magent must be reachable from the Magent runtime.
Container `localhost` is that container, not your Docker host. Native `localhost`
is the native host. Docker Desktop provides `host.docker.internal`; do not assume
that name exists in every Linux Engine deployment. Never mount the Docker socket
into Magent to make service discovery work.
## HTTPS and reverse proxy
Magent needs its own origin, such as `https://magent.example.com`. These examples
serve at `/`, not under a `/magent` subpath. Do not put a second login portal in
front of the API without testing cookies and redirects.
If [Caddy](https://caddyserver.com/docs/quick-starts/reverse-proxy) runs directly
on the same host as the frontend, the site block is:
```caddyfile
magent.example.com {
reverse_proxy 127.0.0.1:3000
}
```
Point public DNS to your proxy's public address and make its certificate
validation ports reachable as required by your Caddy deployment. Validate and
reload your existing proxy configuration, preserving other sites. If the proxy
is itself a container or runs elsewhere, `127.0.0.1` refers to that proxy: use a
reachable Magent address/shared network instead. Do not blindly replace an
existing proxy configuration with this single block.
For an existing [nginx](https://nginx.org/en/docs/http/ngx_http_proxy_module.html)
HTTPS server with certificates already configured, use a `location /` that
proxies to `http://127.0.0.1:3000`, preserves `Host`, sets
`X-Forwarded-Proto $scheme` and `X-Forwarded-For $proxy_add_x_forwarded_for`,
uses `proxy_read_timeout 180s`, disables proxy buffering for streaming responses,
and permits `client_max_body_size 34m` for encrypted restore uploads. TLS key
paths and certificate issuance are operator-owned; Magent does not create them.
Do not add a second CSP that blocks Magent's nonce-authorized scripts.
## First administrator and apps
1. Wait for frontend and API health checks to pass, then open `/setup` at the
exact address your users will use.
2. Obtain the private setup token through the console for your installation
method. Containers generate it automatically; native/manual installations
generate and persist it in their private backend configuration. The
**Get setup token** button is console help, not a public token-retrieval API.
3. Confirm the URL and create a local administrator with a unique password of
at least 12 characters. Never share the token in a ticket or screenshot.
4. Configure only the integrations you need and use **Save & test**. Optional
integrations can be skipped. Review preferences and finish setup.
5. Create an encrypted backup, keep its passphrase separately and test recovery.
Container-managed installations save their URL and derive CORS/cookie behavior
from it. **Native/manual installations must configure URL, CORS and cookie HTTPS
settings explicitly**; changing a wizard field does not edit an environment
file. If moving from HTTP to HTTPS, update both native environment files and
restart the services as described in their guide.
## Operations and troubleshooting
Use [backup and recovery](installation-and-recovery.md) for exports/restores and
your selected guide for restarts, upgrades and rollback. Keep the original
database, private signing/encryption keys and deployment configuration. A new
empty volume or regenerated keys is not an upgrade. Never repair a login problem
by deleting the database or turning off origin protections.
| Symptom | Check |
| --- | --- |
| Setup token is rejected | Correct instance/token, no admin already created, no leading/trailing paste errors; manual env was actually loaded |
| Login rejected or cross-origin error | Exact browser origin, manual CORS, application URL and HTTP/HTTPS cookie settings agree |
| Page has huge logo/no styles or hangs loading | Browser Network/Console for CSS/JS/CSP failures; standalone static/public files copied; HTTP URL explicit where required |
| `/api` returns 502 | API health, frontend's build-time backend address, container network or native loopback listener |
| Database/branding/backup permission error | Correct unprivileged owner and persistent data path; native working directory matters for assets |
| Login disappears after restart | Same volume/database and keys retained; correct cookie origin; not alternating between different instances |
| Restore upload rejected | Archive limits, proxy's 34 MiB request allowance, sufficient private staging space |
| Old UI after updating | Re-pull/recreate the container, or rebuild native standalone files; source changes alone do not replace runtime artifacts |
All supported environment settings are in [ENVIRONMENT.md](ENVIRONMENT.md).
[PUBLIC_RELEASE.md](PUBLIC_RELEASE.md) covers advanced manual-key container
deployments and release verification. Report problems with versions, architecture,
installation method and sanitized errors—not credentials or database contents.
## Validation notes
Checked on 20 September 2026:
- The prebuilt and source-build Compose configurations passed Docker Compose
validation. Documented shell examples and relative links were checked.
- The native foreground path was smoke-tested on Windows with Python 3.14 and
Node.js 24: first-admin setup, browser assets, login, origin checks, API proxy
and persistence after a backend restart passed.
- Linux systemd examples passed static directive validation. They were not
started end-to-end on a Linux host in this check; install the required
runtimes and verify their executable paths before enabling the services.
- The macOS foreground instructions were reviewed but not runtime-tested.
+179
View File
@@ -0,0 +1,179 @@
# Foreground installation: Linux, macOS and Windows
This runs Magent directly from source without Docker or Portainer. It is useful
for local evaluation and development; closing the terminals stops the services.
For a Linux service that starts at boot, use [native production](NATIVE_INSTALL.md).
No Windows Service or macOS launchd package is supplied. Use a private local
directory, not a shared/synced folder containing real production data.
Install Python **3.14**, Node.js **24** with npm, and Git. The commands below are
split by shell; do not paste Bash line continuations into PowerShell. Do not
connect a development checkout to production credentials/databases.
## Get the source and dependencies
Linux/macOS (Bash/zsh):
```sh
git clone --branch release --single-branch https://git.amslabs.net/Rephl3x/Magent.git magent
cd magent
python3.14 -m venv .venv
.venv/bin/python -m pip install -r backend/requirements.txt
```
Windows (PowerShell, with Python's `py` launcher installed):
```powershell
git clone --branch release --single-branch https://git.amslabs.net/Rephl3x/Magent.git magent
Set-Location magent
py -3.14 -m venv .venv
& .\.venv\Scripts\python.exe -m pip install -r backend\requirements.txt
```
If `py` is unavailable, use the full path to your Python 3.14 executable instead.
No activation script or machine-wide execution-policy change is required. Confirm
`node --version` reports 24.x. Native dependency installation may need compiler
prerequisites when wheels are unavailable for your CPU/OS.
## Configure the backend
For a fresh local database, generate three independent values in your **private
terminal**. Replace `python3.14` below with `py -3.14` on Windows:
```sh
python3.14 -c "import secrets; print(secrets.token_urlsafe(48))"
python3.14 -c "import secrets; print(secrets.token_urlsafe(48))"
python3.14 -c "import base64,secrets; print(base64.urlsafe_b64encode(secrets.token_bytes(32)).decode())"
```
The first is `JWT_SECRET`, the second is `SETUP_TOKEN`, and the third is
`SETTINGS_ENCRYPTION_KEY`. Do not paste them into chat/logs/issues. In an editor,
create `backend/.env` with the following contents, replacing all three placeholders:
```dotenv
JWT_SECRET=PASTE_FIRST_RANDOM_VALUE
SETUP_TOKEN=PASTE_SECOND_RANDOM_VALUE
SETTINGS_ENCRYPTION_KEY=PASTE_THIRD_RANDOM_VALUE
MAGENT_MANAGED_SECRETS=false
MAGENT_APPLICATION_URL=http://127.0.0.1:3000
CORS_ALLOW_ORIGIN=http://127.0.0.1:3000
AUTH_COOKIE_SECURE=false
API_DOCS_ENABLED=false
SQLITE_PATH=data/magent.db
LOG_FILE=data/magent.log
BRANDING_SOURCE=data
```
On Linux/macOS restrict the file with `chmod 600 backend/.env` and use a private
checkout (`umask 077` before creating local data). On Windows restrict the folder
and `.env` to your account using NTFS security permissions; Unix `chmod` is not
a substitute for Windows ACLs. The repository ignores `backend/.env` and
`backend/data/`, but Git ignore rules are not encryption or access control.
Use the same keys and database when restarting. Do not recreate `.env` during an
upgrade. For isolated testing without background imports, add
`BACKGROUND_TASKS_ENABLED=false`; omit it for normal operation after setup.
Keep `ADMIN_PASSWORD` and `MAGENT_RUNTIME_MANAGED` unset.
These examples deliberately use **127.0.0.1**, not `localhost`. Open that exact
origin in the browser; mixing the names can break origin checks/cookies.
## Terminal 1: start the API
Start in the checkout root. The working directory below puts all local data in
`backend/data`. `--env-file` explicitly loads the private file; the application
does not discover it automatically.
Linux/macOS:
```sh
cd backend
../.venv/bin/python -m uvicorn app.main:app --env-file .env --host 127.0.0.1 --port 8000 --workers 1
```
Windows PowerShell:
```powershell
Set-Location backend
& ..\.venv\Scripts\python.exe -m uvicorn app.main:app --env-file .env --host 127.0.0.1 --port 8000 --workers 1
```
Leave this process running. There must be only one backend instance using the
database. `--reload` is intentionally not used for installation/restore checks.
## Terminal 2: build and start the web frontend
Open a second terminal at the checkout root. The API address must be set before
building because it is compiled into the frontend's rewrites. The application
URL must also be present in the frontend runtime for this deliberate HTTP mode.
Do not load the backend `.env` into this terminal.
Linux/macOS:
```sh
cd frontend
export BACKEND_INTERNAL_URL=http://127.0.0.1:8000
export NEXT_PUBLIC_API_BASE=/api
export NEXT_TELEMETRY_DISABLED=1
export MAGENT_APPLICATION_URL=http://127.0.0.1:3000
npm ci --include=dev
NODE_ENV=production npm run build
cp -R public .next/standalone/
cp -R .next/static .next/standalone/.next/
HOSTNAME=127.0.0.1 PORT=3000 NODE_ENV=production node .next/standalone/server.js
```
Windows PowerShell:
```powershell
Set-Location frontend
$env:BACKEND_INTERNAL_URL = 'http://127.0.0.1:8000'
$env:NEXT_PUBLIC_API_BASE = '/api'
$env:NEXT_TELEMETRY_DISABLED = '1'
$env:MAGENT_APPLICATION_URL = 'http://127.0.0.1:3000'
$env:NODE_ENV = 'production'
npm.cmd ci --include=dev
npm.cmd run build
Copy-Item -LiteralPath public -Destination .next\standalone\ -Recurse -Force
Copy-Item -LiteralPath .next\static -Destination .next\standalone\.next\ -Recurse -Force
$env:HOSTNAME = '127.0.0.1'
$env:PORT = '3000'
node .next\standalone\server.js
```
Only continue to the next command after the previous one succeeds. The standalone
server needs both copied asset directories; a successful HTML response without
them can still produce an unstyled, unusable page.
For actual frontend development, stop the standalone server and use
`npm run dev -- --hostname 127.0.0.1 --port 3000` with the same backend/public URL
variables. On PowerShell set `$env:NODE_ENV = 'development'` first and use
`npm.cmd run dev -- --hostname 127.0.0.1 --port 3000`; on POSIX prefix the command
with `NODE_ENV=development`. Do not expose the development server
publicly or treat a dev-mode test as a production-build test.
## Verify, set up and retain data
Open `http://127.0.0.1:3000/api/health` (expect `{"status":"ok"}`), then
`http://127.0.0.1:3000/setup`. Enter your `SETUP_TOKEN`, create the administrator
and configure apps. The setup help dialog's container command is not used here;
use the token from your manual `.env`. Remove only `SETUP_TOKEN` after creating
the administrator and restart the API.
Inspect the browser console/network panel for failed scripts, styles or API
requests. Check `/api/setup/status` and a successful sign-in. Restart both
processes and verify the account and settings remain; do not create a second
database accidentally by starting the backend from a different directory.
Ctrl+C stops each process. Keep **backend/data and backend/.env together** for
this local installation. Source deletion, `git clean` or a new checkout does not
preserve untracked data for you. For upgrades, back up first, stop both processes,
update the source/dependencies, rebuild and copy the frontend assets again, then
restart with the original state and keys.
Portable [backup/restore](installation-and-recovery.md) works here too. Restart
the API process after staging a restore and recheck the destination URL. Take
offline snapshots only while the backend is stopped. To move a trial into
production, follow the native/container guide for a fresh destination and restore
a compatible encrypted backup; do not copy a Windows venv or native frontend
dependencies into a Linux installation.
+253
View File
@@ -0,0 +1,253 @@
# Native Linux installation (no Docker)
This is a manual, single-host production recipe for a Linux server with systemd.
Neither Docker nor Portainer is required. For a terminal-only trial, Windows or
macOS, use [foreground installation](LOCAL_DEVELOPMENT.md). See the
[installation overview](INSTALLATION.md) for platform limits and networking.
The operator manages OS updates, Python/Node, private keys, the reverse proxy
and service lifecycle. The systemd files below are reviewable examples, not an
automatic installer; adapt executable paths to your host and validate locally.
## 1. Prerequisites and layout
Install **Python 3.14** with venv/pip, **Node.js 24** with npm, Git, curl and a
trusted TLS reverse proxy. Follow [Python](https://www.python.org/downloads/)
and [Node.js](https://nodejs.org/en/download) instructions for your OS; distribution
default packages may be older. Install both runtimes at service-accessible system
paths outside `/home` and `/root`; a venv linked to a user-private pyenv/uv Python
can be hidden by the units' `ProtectHome` setting. Do not replace the OS's own Python. Native wheels
are architecture-dependent; if pip/npm need compilation, install the appropriate
compiler/library prerequisites from the dependency maintainers rather than
silently changing pinned versions. Do not use `sudo pip install` into system Python.
```sh
python3.14 --version
python3.14 -m venv --help
node --version
npm --version
command -v node
```
This recipe uses:
| Path | Purpose |
| --- | --- |
| `/opt/magent` | Release source, Python venv, frontend dependencies/build |
| `/etc/magent/backend.env` | Private backend keys and deployment configuration |
| `/etc/magent/frontend.env` | Frontend address/bind settings; no backend secrets |
| `/var/lib/magent/data` | Persistent SQLite, logs, branding, artwork and restore staging |
Create a dedicated account and directories on a **fresh** host. If the account
or paths already exist, inspect and reuse the intended installation; do not
overwrite its configuration, clone into it or change ownership blindly.
```sh
sudo useradd --system --user-group --create-home --home-dir /var/lib/magent --shell /usr/sbin/nologin magent
sudo install -d -o magent -g magent -m 0755 /opt/magent
sudo install -d -o root -g root -m 0700 /etc/magent
sudo install -d -o magent -g magent -m 0700 /var/lib/magent/data
sudo -u magent git clone --branch release --single-branch https://git.amslabs.net/Rephl3x/Magent.git /opt/magent
sudo -u magent git -C /opt/magent rev-parse HEAD
sudo -u magent python3.14 -m venv /opt/magent/.venv
sudo -u magent /opt/magent/.venv/bin/python -m pip install -r /opt/magent/backend/requirements.txt
```
Record the checked-out commit. Use the release branch or a reviewed release
commit, not the private development/deployment branches. The native API needs
`backend/requirements.txt`, not Docker's Supervisor dependency file. Python
virtual environments should be recreated at their final path rather than moved.
See [Python venv documentation](https://docs.python.org/3.14/library/venv.html).
## 2. Create private configuration once
Choose the final URL first, for example `https://magent.example.com`. DNS and TLS
are configured separately in your reverse proxy. The native mode does not use
`container_bootstrap` or generate keys automatically.
For a **fresh installation only**, run this standard-library script to create
independent keys without printing them. It refuses to overwrite an existing file.
The default URL below is an example and must be edited before starting services.
```sh
sudo python3.14 - <<'PY'
import base64
import os
from pathlib import Path
import secrets
path = Path('/etc/magent/backend.env')
values = {
'JWT_SECRET': secrets.token_urlsafe(48),
'SETTINGS_ENCRYPTION_KEY': base64.urlsafe_b64encode(secrets.token_bytes(32)).decode(),
'SETUP_TOKEN': secrets.token_urlsafe(48),
'MAGENT_MANAGED_SECRETS': 'false',
'MAGENT_APPLICATION_URL': 'https://magent.example.com',
'CORS_ALLOW_ORIGIN': 'https://magent.example.com',
'AUTH_COOKIE_SECURE': 'true',
'API_DOCS_ENABLED': 'false',
'SQLITE_PATH': '/var/lib/magent/data/magent.db',
'LOG_FILE': '/var/lib/magent/data/magent.log',
'BRANDING_SOURCE': 'data',
}
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
with os.fdopen(fd, 'w') as stream:
stream.write(''.join(f'{name}={value}\n' for name, value in values.items()))
print('Created private backend configuration; edit the example URL before starting.')
PY
sudo install -o root -g root -m 0600 /opt/magent/deploy/native/magent-frontend.env.example /etc/magent/frontend.env
sudoedit /etc/magent/backend.env /etc/magent/frontend.env
```
The [backend template](../deploy/native/magent-backend.env.example) shows the
same fields with placeholders for reference; never run with those placeholders.
Keep both files private and keep an encrypted off-host copy of backend keys.
Run the `install` command above only for a new frontend environment file; during
upgrades retain your existing file rather than copying the example again.
Set `MAGENT_APPLICATION_URL` in **both files**, and backend `CORS_ALLOW_ORIGIN`,
to exactly the browser origin: scheme, hostname and any non-default port, without
a path or trailing slash. For HTTPS set `AUTH_COOKIE_SECURE=true`; for a deliberate
trusted-LAN HTTP installation set it `false` and use the explicit `http://` URL
in both files. The frontend uses this to avoid inappropriate CSP HTTPS upgrades.
Do not use wildcard CORS or disable CSRF protections to fix an address mismatch.
Leave `ADMIN_PASSWORD` unset so the wizard creates the first administrator.
Leave the internal `MAGENT_RUNTIME_MANAGED` flag unset. API docs remain disabled.
All optional integration/environment controls are in [ENVIRONMENT.md](ENVIRONMENT.md);
configure app credentials through the wizard instead of copying every example
variable into these files.
**A `.env` file is not automatically loaded by the backend.** The systemd unit
loads `backend.env` explicitly. The frontend must never load that backend file
or receive secrets in `NEXT_PUBLIC_*` variables.
## 3. Build the frontend
Run the build as the unprivileged service account. The backend address must be
present **at build time**: otherwise this project defaults to Docker's
`http://backend:8000`, which does not normally resolve on a native host.
```sh
sudo -u magent sh -c 'cd /opt/magent/frontend && npm ci --include=dev'
sudo -u magent sh -c 'cd /opt/magent/frontend && BACKEND_INTERNAL_URL=http://127.0.0.1:8000 NEXT_PUBLIC_API_BASE=/api NEXT_TELEMETRY_DISABLED=1 NODE_ENV=production npm run build'
sudo -u magent sh -c 'cd /opt/magent/frontend && cp -R public .next/standalone/ && cp -R .next/static .next/standalone/.next/'
sudo -u magent mkdir -p /opt/magent/frontend/.next/standalone/.next/cache
```
Keep the build tools/dev dependencies until the build is complete. Do not serve
the source with `next dev` in production. This project uses Next's **standalone**
output: run its `server.js`, with the `public` and `.next/static` directories
copied as above. Changing the backend host/port requires rebuilding this bundle,
not merely editing its runtime environment. See [Next standalone deployment](https://nextjs.org/docs/app/api-reference/config/next-config-js/output).
## 4. Install and validate the services
The supplied units run as `magent`, bind to loopback, use a read-only system view,
private temporary directories and restricted writable paths. The backend has
**one worker**. Its fixed working directory is important: artwork/branding use
`cwd/data`, independently of `SQLITE_PATH`. Do not replace that directory with a
symlink; portable backup rejects a symlinked asset root.
```sh
sudo install -o root -g root -m 0644 /opt/magent/deploy/native/magent-backend.service /etc/systemd/system/magent-backend.service
sudo install -o root -g root -m 0644 /opt/magent/deploy/native/magent-frontend.service /etc/systemd/system/magent-frontend.service
sudoedit /etc/systemd/system/magent-frontend.service
sudo systemd-analyze verify /etc/systemd/system/magent-backend.service /etc/systemd/system/magent-frontend.service
sudo systemctl daemon-reload
sudo systemctl enable --now magent-backend.service magent-frontend.service
```
Before verification, make frontend `ExecStart` match the system-wide Node 24 path
reported by `command -v node` (`/usr/bin/node` in the template). Service managers
do not inherit an interactive nvm shell; install Node at a service-accessible
system path. Likewise adapt the source/venv paths if you changed this layout.
Do not remove hardening settings just to mask an incorrect writable path.
Inspect [systemd execution settings](https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html)
when adapting units to your distribution. `After` sets ordering, not application
readiness: confirm the health checks below before exposing the site.
```sh
sudo systemctl status magent-backend.service magent-frontend.service --no-pager
curl --fail http://127.0.0.1:8000/health
curl --fail http://127.0.0.1:3000/api/health
curl --fail http://127.0.0.1:3000/api/setup/status
sudo journalctl -u magent-backend.service -u magent-frontend.service -n 100 --no-pager
```
Both health endpoints should report `{"status":"ok"}`. A fresh setup status has
`setup_required` and `needs_admin` set to `true`. Check logs locally, but sanitize
them before sharing. The frontend is not a standalone static site: both processes
must stay running. It is normal to see a temporary API error if the backend is
still starting.
## 5. Configure HTTPS and finish setup
Use the [reverse-proxy instructions](INSTALLATION.md#https-and-reverse-proxy) to
send your chosen HTTPS hostname to `127.0.0.1:3000`. Keep backend port 8000 private.
For a remote browser without a proxy, use an SSH tunnel for a local trial or
deliberately change the frontend bind address and matching URL for trusted-LAN
use; the production units intentionally are not LAN listeners by default.
Retrieve only the setup token in your private administrative terminal:
```sh
sudo sed -n 's/^SETUP_TOKEN=//p' /etc/magent/backend.env
```
Open the final browser URL, create the administrator, configure apps and finish
the wizard. Native installations use this manually persisted token, not the
container command shown in the managed-install part of the help dialog. After
administrator creation, remove `SETUP_TOKEN` using `sudoedit` and restart the
backend. **Do not remove/regenerate JWT_SECRET or SETTINGS_ENCRYPTION_KEY.**
Restarting never reopens first-admin signup on an existing database.
```sh
sudoedit /etc/magent/backend.env
sudo systemctl restart magent-backend.service
```
## Routine operation, backup and restore
- Start/stop/restart with `systemctl`; enablement starts services after boot.
Check the journal and `/var/lib/magent/data/magent.log` for backend errors.
- Use [encrypted application backups](installation-and-recovery.md). Portable
exports do not include the environment files, deployment keys or TLS keys;
back those up separately and protect their passphrases.
- For an offline disaster-recovery snapshot, stop both Magent services and back
up `/var/lib/magent/data`, `/etc/magent` and the exact source revision/unit
configuration using your trusted backup tool, then start services again.
Do not copy a live SQLite file and assume it is consistent.
- A staged UI restore takes effect when you restart **magent-backend.service**.
Keep one worker and no other writers, keep destination keys unchanged, then
verify restored accounts and integrations. Native/manual restore may import
the source's saved application URL: recheck **Hosting & proxy** against your
destination environment and frontend URL after recovery.
## Upgrade and roll back
Plan a maintenance window; this is not a rolling multi-worker deployment.
1. Record `git -C /opt/magent rev-parse HEAD`, back up the application and private
environment, and read migration/release notes. Keep the previous source and
runtime dependency versions available.
2. Stop both services. Fetch `release` as the source owner and review the exact
intended commit; use `git merge --ff-only origin/release` only for a clean
release checkout. Do not force-reset local changes.
3. Install the new pinned backend requirements into the existing venv, or create
a replacement venv at its final path if the Python version changed. Re-run
**all** frontend dependency/build/static-copy steps above. Keep the same data
directory and private environment; do not rerun initial key generation.
4. Review any unit changes, validate and `daemon-reload` if needed, start services
and check API health, setup/login, UI assets, integrations and backups.
For a rollback, stop both services, restore the recorded compatible source and
dependency/build artifacts, and keep the original keys/data. If the upgrade
changed the database incompatibly, use the matching pre-upgrade database backup
with that older version; code-only rollback is not always safe. Portable restore
should first use the same application version that created the backup.
To retire a native installation, disable/stop its two units first. Retain the
data and private environment until an off-host restore has been verified. Do not
delete `/var/lib/magent` as a troubleshooting step.
+3
View File
@@ -1,5 +1,8 @@
# Install with Portainer
Portainer is optional. See [all installation methods](INSTALLATION.md) for
[Docker CLI/Compose](DOCKER.md) or [native installation](NATIVE_INSTALL.md).
For a **fresh installation**, paste [compose.yml](../compose.yml) into a new
Portainer stack and deploy with **no environment variables**. The stack names
`image: rephl3xnz/magent:latest` directly. Portainer pulls that prebuilt Docker Hub image; Magent
+11 -4
View File
@@ -1,7 +1,13 @@
# 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
Start with [installation methods](INSTALLATION.md): [Docker Compose/CLI](DOCKER.md),
[Portainer](PORTAINER.md), [native Linux services](NATIVE_INSTALL.md), or
[foreground Windows/macOS/Linux](LOCAL_DEVELOPMENT.md). This document retains
the advanced container/manual-key and release-maintenance details.
The container distribution runs as one non-root Linux container containing the
Python API and Next.js frontend; a native deployment runs them as two services.
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.
@@ -22,8 +28,9 @@ 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](../compose.yml) and follow the [Portainer guide](PORTAINER.md).
For a prebuilt **Docker Compose or Portainer** installation, use the image-only
root [compose.yml](../compose.yml) and follow the [Docker](DOCKER.md) or
[Portainer](PORTAINER.md) 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
+15 -29
View File
@@ -2,42 +2,28 @@
## Fresh installation
For a new Portainer installation without a Dockerfile or `.env`, use the
[single-file stack guide](PORTAINER.md). It generates persistent deployment
secrets and provides a console-only setup-token command. The root stack pulls
`rephl3xnz/magent:latest` with no environment inputs. Confirm the application URL
alongside the token when creating your first administrator; managed CORS and
cookie security follow that URL automatically. SQLite is fixed at
`/app/data/magent.db`, and API documentation remains disabled. Leave the Compose
runtime-security defaults unchanged. The updated image still needs publishing
before `latest` provides this behaviour; repository changes alone do not deploy
or publish it. Record deployed digests because `latest` is mutable.
Choose [Docker Compose/CLI](DOCKER.md), [Portainer](PORTAINER.md),
[native Linux services](NATIVE_INSTALL.md) or [foreground source installation](LOCAL_DEVELOPMENT.md)
from the [installation overview](INSTALLATION.md). Follow that guide for private
configuration, startup, health checks and the correct setup-token command.
The **manual-secret and source-build instructions below** remain supported for
other deployments. All environment options and defaults are documented in
[ENVIRONMENT.md](ENVIRONMENT.md); they are not required inputs to the managed
Portainer template.
The managed container image is published as `rephl3xnz/magent:latest`; its root
Compose file has no environment inputs and retains explicit security defaults.
Managed containers persist generated secrets and confirm their application URL
when creating the first administrator. Native/manual installations instead load
their own private keys, exact URL/CORS and HTTP/HTTPS cookie policy explicitly.
See [ENVIRONMENT.md](ENVIRONMENT.md) for all environment options. Neither mode
configures DNS, installs a reverse proxy or issues TLS certificates.
Start with `.env.example`. Generate independent random values for `JWT_SECRET` and `SETUP_TOKEN` (at least 32 characters each), plus a Fernet `SETTINGS_ENCRYPTION_KEY`. Never deploy the example placeholders. Keep the environment file private.
```bash
python -c "import secrets; print(secrets.token_urlsafe(48))"
python -c "import secrets; print(secrets.token_urlsafe(48))"
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
```
The first two commands produce the JWT secret and setup token respectively. The third requires the backend dependencies. Alternatively generate the Fernet key using Python's standard library: `python -c "import base64, secrets; print(base64.urlsafe_b64encode(secrets.token_bytes(32)).decode())"`.
For a manual-secret installation, set the correct browser-facing `CORS_ALLOW_ORIGIN`, `MAGENT_APPLICATION_URL`, cookie HTTPS settings and host paths before starting. Changing the application URL in its wizard does not replace its explicit environment CORS policy. Managed Portainer installations instead confirm their origin during token-authorized first-admin setup, and automatically follow that saved origin for CORS and cookie security. Neither mode changes reverse-proxy configuration or creates certificates.
After `docker compose -f compose.yml -f compose.build.yml up -d --build` for a source build, visit the frontend. A new database redirects to `/setup`:
Once the selected installation is healthy, visit its frontend. A new database
redirects to `/setup`:
1. Enter `SETUP_TOKEN` and create a local administrator with a unique password of at least 12 characters. Alternatively, set `ADMIN_USERNAME` and `ADMIN_PASSWORD` in the environment before the first start, then sign in with that account.
2. Expand each app you use: Jellyfin, Seerr/Jellyseerr, Sonarr, Radarr, Prowlarr, qBittorrent, Bazarr and Jellystat. Enter its internal address and credentials, then **Save & test**. For Sonarr/Radarr, a successful check loads quality profiles and root folders.
3. Set site access, request refresh/retention and optional SMTP preferences. Invite signup remains invite-only.
4. Review and finish. Magent starts its configured background jobs, unless `BACKGROUND_TASKS_ENABLED=false`.
Use server-reachable addresses: `localhost` in a container refers to that container. Optional apps can be skipped. Each successful save persists; closing the tab leaves setup resumable. Unsaved form fields are not retained. Remove `SETUP_TOKEN` after finishing. Bootstrap is permanently disabled after setup, and cannot replace an existing administrator. Administrators can revisit the wizard from Settings without resetting the installation.
Use server-reachable addresses: `localhost` in a container refers to that container. Optional apps can be skipped. Each successful save persists; closing the tab leaves setup resumable. Unsaved form fields are not retained. Manual/native operators remove the environment `SETUP_TOKEN` after administrator creation and restart the backend. Managed-container operators must not edit/delete their generated secrets file; the console command and bootstrap refuse token reuse after the first administrator exists. Administrators can revisit the wizard from Settings without resetting the installation.
Upgrades with an existing users table are marked configured automatically. Setup status reveals only whether setup is needed and whether the first administrator is missing. Configuration and wizard progress require administrator authentication. First-admin creation uses a constant-time token comparison, persistent rate limits and a database transaction to prevent concurrent claims.
@@ -64,7 +50,7 @@ The frontend and backend accept up to 34 MiB for the whole multipart request, in
1. Make a fresh backup of the destination. Stop external writes/other backend processes sharing its SQLite file. The supplied deployment uses one backend worker; do not run restore against a multi-worker/shared-database deployment.
2. Sign in as an administrator, select a `.magent-backup`, enter its passphrase and type `RESTORE`. A fresh replacement installation must first create its temporary administrator through `/setup`; then use the **Restore it here** link before connecting apps.
3. Upload and stage the restore. Magent checks authentication, encrypted integrity, archive paths and sizes, checksums, SQLite integrity, schema compatibility and an active restored administrator. Live data is unchanged at this point. A pending restore can be cancelled from the same page.
4. Restart the application using your normal deployment process, for example `docker compose restart magent` for a source build, or restart the container in Portainer. The UI never restarts a server automatically.
4. Restart the backend using your installation guide: for the documented Compose project, `docker compose -f compose.yml -p magent restart magent`; for direct Docker, `docker restart magent`; in Portainer, restart its Magent container; for native Linux, `sudo systemctl restart magent-backend.service`. Substitute your actual project/container/unit names. Foreground users stop and relaunch their API process with the same working directory and private environment. The UI never restarts a server automatically.
5. On startup, before schema initialization or workers, Magent creates a private rollback copy, replaces the database/selected assets and records the result. Failed or interrupted replacement is rolled back using a durable journal. Review the backend logs if startup stops.
6. Sign in with an account from the restored backup, verify Settings/service checks, requests, issues and invite policy, then create a new backup. Old sessions and password-reset tokens are invalidated. Existing invite records and links are retained, with their original expiry and usage state.