docs(install): cover Docker and native deployments
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user