Native Linux installation¶
LicenseTrack can run directly on a Linux host as a systemd service. This path does not use Docker or Podman.
Supported baseline¶
- Debian 13 or Ubuntu 22.04 LTS, x86_64
- systemd
- CPython 3.12, 3.13, or 3.14 with the
venv, SSL, and SQLite modules curl,tar, and standard GNU/Linux user-management tools- A TLS-terminating reverse proxy for network-reachable production use
The official native release archive contains the compiled frontend and offline wheelhouses for all supported Python ABIs. The installer selects the matching runtime and wheelhouse automatically, so Node.js is not required when using that archive.
Distribution Python
Debian 13 supplies supported CPython 3.13 packages; install its matching venv package before running the installer. Ubuntu 22.04 does not ship a supported LicenseTrack Python version in its standard repositories, so install and maintain CPython 3.12, 3.13, or 3.14 according to your organisation's package policy. Do not replace /usr/bin/python3; system tools should continue using the distribution Python.
Verify the interpreter you intend to use (this example uses Python 3.12):
Install from the native release archive¶
Download both the native archive and SHA256SUMS from the GitHub release. Verify the archive before extracting it:
sha256sum --check SHA256SUMS
tar -xzf licensetrack-native-<version>-linux-x86_64.tar.gz
cd licensetrack-native-<version>-linux-x86_64
./install.sh --verify-only
sudo ./install.sh
The installer offers two modes:
| Mode | Intended use | Configuration |
|---|---|---|
| Standard (recommended) | Most production installations | Prompts only for the browser-facing URL, reverse-proxy confirmation when needed, and initial local admin password. Uses safe runtime defaults and binds to 127.0.0.1:8000. |
| Advanced | Custom ports, troubleshooting, larger limits, or isolated test environments | Also prompts for bind address, port, log level, session lifetime, upload/extension limits, allowed extensions, API documentation exposure, session-cookie behavior, and test-only OIDC network allowances. |
Press Enter at the mode prompt to choose Standard, or select a mode explicitly:
Both modes generate the JWT signing secret automatically and protect the resulting environment file. SMTP credentials and OIDC provider/client details remain application-managed settings: configure them after first login under Settings. Advanced mode can enable plain-HTTP or private-network OIDC discovery for an isolated test environment, but those allowances should remain disabled in production.
After installation:
Install from GitHub's source archive¶
The automatic tag ZIP is source-only. Its installer builds the production frontend on the server, so this path additionally requires Node.js 22 and npm:
Use the native release archive for production when possible. It is built and checksummed by the release workflow and does not install frontend build tooling on the server.
Unattended installation¶
Store the initial admin password in a root-readable file and supply the public URL explicitly:
sudo install -m 600 /dev/null /root/licensetrack-admin-password
sudo editor /root/licensetrack-admin-password
sudo ./install.sh \
--yes \
--network-mode reverse-proxy \
--public-url https://licenses.example.com \
--admin-password-file /root/licensetrack-admin-password
sudo rm /root/licensetrack-admin-password
The explicit network mode confirms that an existing reverse proxy will forward
the public URL to LicenseTrack's loopback listener. An unattended install
rejects a non-local public URL with a loopback bind unless
--network-mode reverse-proxy is present.
The installer intentionally does not accept the password as a command-line argument, where it would be visible in process listings and shell history.
--yes selects Standard mode when no mode is supplied. An unattended Advanced install accepts the same settings as flags instead of prompting. For example, this isolated HTTP test configuration binds to the LAN and permits a private plain-HTTP identity provider:
sudo ./install.sh \
--advanced \
--yes \
--network-mode direct-network \
--bind-host 0.0.0.0 \
--port 8000 \
--public-url http://192.168.0.247:8000 \
--allow-http-oidc-discovery \
--allow-private-oidc-discovery \
--no-session-cookie-secure \
--admin-password-file /root/licensetrack-admin-password
direct-network defaults the bind address to 0.0.0.0 when
--bind-host is omitted, but it never opens the host firewall. Restrict direct
access to an isolated or otherwise trusted network.
Run ./install.sh --help for every Advanced automation flag. Command-line flags contain no secret values; application integration secrets are entered later through LicenseTrack's Settings UI.
Filesystem layout¶
| Purpose | Path |
|---|---|
| Versioned releases | /opt/licensetrack/releases/<version>/ |
| Active release link | /opt/licensetrack/current |
| SQLite database | /var/lib/licensetrack/licenses.db |
| Uploaded documents | /var/lib/licensetrack/storage/ |
| Official Extension packages | /var/lib/licensetrack/plugins/ |
| Database backups | /var/lib/licensetrack/backups/ |
| Upgrade snapshots | /var/backups/licensetrack/upgrades/ |
| Protected environment | /etc/licensetrack/licensetrack.env |
| Install state | /etc/licensetrack/install.json |
| systemd unit | /etc/systemd/system/licensetrack.service |
Application files are root-owned. The service runs as the unprivileged licensetrack account and can write only its persistent data paths. Journald captures application output.
Installation, upgrade, rollback, backup orchestration, and removal require root because they manage systemd, accounts, protected configuration, and root-owned application paths. The running web application does not run as root:
- release code and its virtual environment are root-owned and not writable by the service account;
/etc/licensetrack/licensetrack.envis root-owned, readable by the service group, and not service-writable;/var/lib/licensetrackis service-owned and contains the mutable database, documents, application backups, and Official Extension data;- native upgrade snapshots under
/var/backups/licensetrackare root-only; and - the systemd service uses
NoNewPrivileges,PrivateTmp,ProtectSystem,ProtectHome, and a restrictiveUMask.
An application compromise can expose or alter LicenseTrack data and read the runtime secrets required by the service. These boundaries prevent that access from automatically granting permission to replace application code, configuration, the systemd unit, or the operator command; they are not a hostile-code sandbox.
Reverse proxy and HTTPS¶
The default loopback binding is deliberate. Put nginx, Caddy, or another TLS-terminating reverse proxy in front of 127.0.0.1:8000. The public URL entered during installation becomes CORS_ORIGINS; HTTPS URLs also enable secure session cookies.
When an interactive install combines a non-local public URL with the loopback
bind, it explains that this is reverse-proxy mode and requires confirmation.
For unattended installation, declare --network-mode reverse-proxy
explicitly. licensetrack doctor reports the effective bind, public URL, and
reachability mode; installations upgraded from an older state receive a
warning until the operator confirms that the inferred reverse-proxy
arrangement is intentional.
Do not expose port 8000 directly to an untrusted network. Route both the SPA and /api/* paths through the same public origin.
Service operations¶
sudo licensetrack start
sudo licensetrack stop
sudo licensetrack restart
sudo licensetrack status
sudo licensetrack logs
sudo licensetrack doctor
sudo licensetrack backup
sudo licensetrack version
The backup command creates the same WAL-safe SQLite backup format used by the application. It does not include uploaded documents. Upgrade snapshots are separate and include the managed data directory, configuration, and any configured external document-storage path. The doctor command reports document record, available-file, and missing-file counts so a database-only restore can be reconciled with managed storage without deleting metadata.
For data-retention choices and complete host cleanup, see Native Linux removal.
First login¶
Open the public URL, sign in as admin, and use the password supplied during installation. Continue with First launch & login.