docs(install): cover Docker and native deployments
This commit is contained in:
@@ -21,6 +21,7 @@ bootstrap-secrets.json
|
|||||||
.magent-secrets-*
|
.magent-secrets-*
|
||||||
data/*
|
data/*
|
||||||
!data/branding/
|
!data/branding/
|
||||||
|
backend/data/
|
||||||
*.tar
|
*.tar
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
*.zip
|
*.zip
|
||||||
|
|||||||
@@ -2,37 +2,54 @@
|
|||||||
|
|
||||||
Self-hosted media requests, viewing stats and issue management for Jellyfin,
|
Self-hosted media requests, viewing stats and issue management for Jellyfin,
|
||||||
Seerr, Sonarr, Radarr and related services. Magent combines a Python/FastAPI API,
|
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
|
## Install
|
||||||
|
|
||||||
Paste [compose.yml](compose.yml) into a Portainer **Docker Standalone** stack.
|
Start with the [installation guide](docs/INSTALLATION.md) to choose a method:
|
||||||
It uses `rephl3xnz/magent:latest`, persists data in a named volume and needs no
|
|
||||||
environment variables or Dockerfile on the user's machine.
|
| 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.
|
**Image availability:** the managed-install image is published on Docker Hub.
|
||||||
Only Linux/amd64 has been validated. `latest` is mutable; record the resolved
|
Only Linux/amd64 has been validated. `latest` is mutable; record the resolved
|
||||||
image digest before updating, or pin an immutable release tag.
|
image digest before updating, or pin an immutable release tag.
|
||||||
|
|
||||||
1. Deploy the stack and wait for the container to become healthy.
|
1. Wait for the container to become healthy and retrieve the token using the
|
||||||
2. In its console, select `/bin/ash` and user `magent`, then run:
|
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
|
||||||
```sh
|
|
||||||
python -m app.container_bootstrap setup-token
|
|
||||||
```
|
|
||||||
|
|
||||||
3. 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.
|
in setup and use the token to create the first administrator.
|
||||||
The **Get setup token** button shows the console instructions and lets you
|
The **Get setup token** button shows the console instructions and lets you
|
||||||
copy the command; it never reveals the token to public visitors.
|
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.
|
be skipped. Save an encrypted backup afterwards.
|
||||||
|
|
||||||
Keep the Compose security block unchanged. Database storage is fixed at
|
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
|
`/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.
|
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),
|
[all environment options](docs/ENVIRONMENT.md),
|
||||||
[backup and restore](docs/installation-and-recovery.md) and
|
[backup and restore](docs/installation-and-recovery.md) and
|
||||||
[advanced installation/upgrades](docs/PUBLIC_RELEASE.md).
|
[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:
|
The source tree contains everything needed to build the application:
|
||||||
|
|
||||||
```sh
|
```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:
|
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.
|
- `backend/tests/` and frontend `*.test.*`: synthetic regression tests.
|
||||||
- `Dockerfile` and `docker/`: multi-stage build and process supervision.
|
- `Dockerfile` and `docker/`: multi-stage build and process supervision.
|
||||||
- `compose.yml`: prebuilt-image install; `compose.build.yml`: source override.
|
- `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,
|
Requests are cached from Seerr, joined to collector/download/library evidence,
|
||||||
normalised into a user-facing state and displayed by the frontend. App settings
|
normalised into a user-facing state and displayed by the frontend. App settings
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
# Optional source build; retain compose.yml's storage and security defaults.
|
# 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:
|
services:
|
||||||
magent:
|
magent:
|
||||||
image: magent:local
|
image: magent:local
|
||||||
|
|||||||
+3
-1
@@ -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.
|
# Configure the site address and connected apps in Magent's setup wizard.
|
||||||
# No Dockerfile, source checkout, .env file or shared default password is needed.
|
# No Dockerfile, source checkout, .env file or shared default password is needed.
|
||||||
# Existing installations must keep their original data mount and keys.
|
# Existing installations must keep their original data mount and keys.
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
@@ -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
@@ -1,6 +1,6 @@
|
|||||||
# Environment variable reference
|
# 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
|
Its image supplies the runtime defaults; use the first-run setup wizard to set
|
||||||
the application URL, connect services and configure notifications. The normal
|
the application URL, connect services and configure notifications. The normal
|
||||||
stack does not need a Dockerfile, source checkout or `.env` file.
|
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,
|
This reference also covers advanced/manual deployments, compatibility aliases,
|
||||||
image-build inputs and repository-only tooling. A variable being listed here
|
image-build inputs and repository-only tooling. A variable being listed here
|
||||||
does **not** mean that it belongs in the public Compose file.
|
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
|
## 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
|
deployment controls, not ordinary editable settings. Container listener ports
|
||||||
are fixed by its process supervisor, not by application settings.
|
are fixed by its process supervisor, not by application settings.
|
||||||
- For manual deployments, environment variables are read at process startup.
|
- For manual deployments, environment variables are read at process startup.
|
||||||
Restart/recreate after changing them. A `.env` file is loaded by the relevant
|
Restart/recreate after changing them. Load the private file through the relevant
|
||||||
Compose template's `env_file`, not automatically discovered by the application.
|
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.
|
Keep manual credentials stable across upgrades and offline restores.
|
||||||
|
|
||||||
Defaults use JSON notation: `null` means unset, `""` means an empty string,
|
Defaults use JSON notation: `null` means unset, `""` means an empty string,
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -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.
|
||||||
@@ -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.
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
# Install with Portainer
|
# 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
|
For a **fresh installation**, paste [compose.yml](../compose.yml) into a new
|
||||||
Portainer stack and deploy with **no environment variables**. The stack names
|
Portainer stack and deploy with **no environment variables**. The stack names
|
||||||
`image: rephl3xnz/magent:latest` directly. Portainer pulls that prebuilt Docker Hub image; Magent
|
`image: rephl3xnz/magent:latest` directly. Portainer pulls that prebuilt Docker Hub image; Magent
|
||||||
|
|||||||
+11
-4
@@ -1,7 +1,13 @@
|
|||||||
# Public installation and release guide
|
# Public installation and release guide
|
||||||
|
|
||||||
Magent runs as one non-root Linux container containing the Python API and the
|
Start with [installation methods](INSTALLATION.md): [Docker Compose/CLI](DOCKER.md),
|
||||||
Next.js frontend. Connect your own media services in the setup wizard; no
|
[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
|
pre-existing Magent account or database is required. Optional
|
||||||
integrations may be skipped. Media files remain in your existing media services.
|
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
|
## Fresh installation
|
||||||
|
|
||||||
For the simplest **Portainer** installation, use the image-only root
|
For a prebuilt **Docker Compose or Portainer** installation, use the image-only
|
||||||
[compose.yml](../compose.yml) and follow the [Portainer guide](PORTAINER.md).
|
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
|
That fresh-install path pulls `rephl3xnz/magent:latest` from Docker Hub with no
|
||||||
environment inputs, automatically persists its private keys and requires no
|
environment inputs, automatically persists its private keys and requires no
|
||||||
Dockerfile or `.env`. Confirm the browser-facing application URL in the
|
Dockerfile or `.env`. Confirm the browser-facing application URL in the
|
||||||
|
|||||||
@@ -2,42 +2,28 @@
|
|||||||
|
|
||||||
## Fresh installation
|
## Fresh installation
|
||||||
|
|
||||||
For a new Portainer installation without a Dockerfile or `.env`, use the
|
Choose [Docker Compose/CLI](DOCKER.md), [Portainer](PORTAINER.md),
|
||||||
[single-file stack guide](PORTAINER.md). It generates persistent deployment
|
[native Linux services](NATIVE_INSTALL.md) or [foreground source installation](LOCAL_DEVELOPMENT.md)
|
||||||
secrets and provides a console-only setup-token command. The root stack pulls
|
from the [installation overview](INSTALLATION.md). Follow that guide for private
|
||||||
`rephl3xnz/magent:latest` with no environment inputs. Confirm the application URL
|
configuration, startup, health checks and the correct setup-token command.
|
||||||
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.
|
|
||||||
|
|
||||||
The **manual-secret and source-build instructions below** remain supported for
|
The managed container image is published as `rephl3xnz/magent:latest`; its root
|
||||||
other deployments. All environment options and defaults are documented in
|
Compose file has no environment inputs and retains explicit security defaults.
|
||||||
[ENVIRONMENT.md](ENVIRONMENT.md); they are not required inputs to the managed
|
Managed containers persist generated secrets and confirm their application URL
|
||||||
Portainer template.
|
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.
|
Once the selected installation is healthy, visit its frontend. A new database
|
||||||
|
redirects to `/setup`:
|
||||||
```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`:
|
|
||||||
|
|
||||||
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.
|
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.
|
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.
|
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`.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user