Browse documentation ↓

Remote server management

Use Servers to inspect host-installed Linux Nginx, review configuration changes, stage signed modules, deploy releases, and verify what is loaded. Exporting an archive alone does not deploy it.

The native module is .so. Build and sign on the management/build machine; install the helper once on the Nginx machine. The portal later manages reviewed changes over SSH.

Management machine, once:

umask 077
mkdir -p .secrets
ssh-keygen -t ed25519 -f .secrets/nginx-deploy -N ''  # dedicated deployment credential
openssl genpkey -algorithm ED25519 -out .secrets/module-signing.pem
openssl pkey -in .secrets/module-signing.pem -pubout -out .secrets/module-public.pem
cargo build --release -p pragma-engine             # builds target/release/pragma-cli
scripts/build-nginx.sh                            # reference Nginx/module build ONLY

Do not repeat key-generation commands over existing key files. The reference build is suitable only for its documented Nginx build/platform. Inspect your target build before selecting/building a compatible module. A module compiled on an incompatible architecture or libc is not fixed by signing it.

Nginx machine, inspect:

/usr/sbin/nginx -V                  # version and exact configure flags
sudo /usr/sbin/nginx -t             # validate the actual config and permissions
sudo /usr/sbin/nginx -T             # effective config; may contain sensitive values
uname -m                           # target architecture
sudo cat /etc/ssh/ssh_host_ed25519_key.pub  # host public key, through trusted console/admin access

Use actual paths if they differ. Independently verify the host key before pinning it in SSH and the portal. Do not treat an unverified network key scan as verification.

Provision the dedicated pragma-deploy account and its restricted authorized key through your normal server administration. Install the verified helper scripts, compatible pragma-cli, and only the public module-signing key on the Nginx host. Here is the one-time bootstrap command, run from a trusted copy of this repository on that host:

sudo install -m 0755 /path/to/compatible/pragma-cli /usr/local/bin/pragma-cli
sudo python3 scripts/remote/bootstrap.py \
  --account pragma-deploy \
  --nginx /usr/sbin/nginx \
  --config /etc/nginx/nginx.conf \
  --prefix /usr/share/nginx \
  --service nginx \
  --validator /usr/local/bin/pragma-cli \
  --module-public-key /path/to/module-public.pem \
  --health-url http://127.0.0.1/health

Replace the health URL with a real, safe endpoint returning 200, and confirm the paths/service first. Bootstrap needs Python 3, sudo, OpenSSL and an existing deployment account; it does not install Nginx or create an account. Keep the deployment account out of general sudo groups. Review /etc/pragmachange-helper.json. The portal's SSH credential must be usable without an interactive passphrase; protect its dedicated private key and restrict the authorized key (for example, restrict).

Management machine, capture build metadata and package a compatible module:

export PRAGMA_PROXY=proxy.internal  # your actual host
ssh -i .secrets/nginx-deploy -o StrictHostKeyChecking=yes "pragma-deploy@$PRAGMA_PROXY" \
  'python3 -c "import subprocess,sys; r=subprocess.run([\"/usr/sbin/nginx\",\"-V\"],capture_output=True); sys.stdout.buffer.write(r.stdout+r.stderr); sys.exit(r.returncode)"' \
  > .secrets/target-nginx-build.txt
python3 scripts/remote/package-module.py \
  --module /path/to/compatible/ngx_http_pragmachange_module.so \
  --nginx-build-output .secrets/target-nginx-build.txt \
  --architecture x86_64 \
  --signing-key .secrets/module-signing.pem \
  --output .secrets/pragma-module.tar.gz

Use the actual architecture from uname -m. Register the server in Servers, with its deployment private key and verified host public key. Inspect it, stage this package, inspect again, prepare integration for selected locations, review the diff, and deploy a selected release. Model-only updates normally require a graceful reload; the portal shows restart requirements for native upgrades. Follow remote operations for verification/recovery semantics.

Deployment behavior and recovery

The first remote transport supports host-installed Nginx on Linux, using a dedicated SSH account. Nginx must handle HTTP; opaque TCP/TLS passthrough is not inspectable by this module.

  1. On the management machine, generate a private credential key file containing 64 hexadecimal characters. Set CREDENTIAL_KEY_FILE to its absolute path and restrict its permissions to 0600. Retain this key with backups: encrypted SSH and provider credentials cannot be recovered without it. Do not reuse PARTITION_SECRET.
  2. On the proxy, install Python 3, OpenSSH server, sudo, OpenSSL and a compatible pragma-cli. Compile the module elsewhere against the exact target Nginx build and platform; the bundled 1.28.0 reference build is not universal.
  3. Generate an Ed25519 artifact-signing key off-host. Install its public key on the proxy. Package a module with scripts/remote/package-module.py, providing the exact captured nginx -V stdout followed by stderr, target architecture, and signing key. The signed manifest binds the binary digest to the target build. The signing key must never be available to the proxy.
  4. Provision an SSH account that has no unrelated sudo privileges. Run scripts/remote/bootstrap.py once as root, supplying --account, --module-public-key, and --health-url. Supply the actual --nginx, --config, --prefix, --validator and --service where defaults differ. Inspect the generated policy at /etc/pragmachange-helper.json. The configured health URL must be a safe read-only endpoint; configure its expected host/status directly in this root-owned policy if needed.
  5. The bootstrap installs root-owned helper code and one no-argument sudo entry. Use an SSH authorized-key restriction such as restrict for the deployment key; the account must not be able to modify helper code, policy, Nginx configuration, or managed artifacts directly. Restrict interactive access separately according to your SSH policy.
  6. Register the account in Servers, including its private SSH key and the independently verified server host public key (ssh-ed25519 AAAA…, without hostname/comment). The controller does not discover and silently trust host keys. Encrypted private keys are never returned by list APIs.
  7. Inspect, stage the signed module, inspect again, select locations, and prepare an integration preview. Select that preview and an existing release, review the diff, then deploy.

Uploaded configuration analysis reports locations but cannot resolve the target’s includes, permissions, TLS files or loaded modules. Target inspection and validation are mandatory. Automatic integration supports a single top-level HTTP block and ordinary locations, including discovered include files. Conditional/nested or ambiguous structures require a manual reviewed integration. Only the necessary Pragma directives and managed include files are added.

Module files and model bundles are separate. Ordinary model releases validate and reload. Existing native-module upgrades use Prepare module upgrade, require explicit restart acknowledgement, and use the fixed service restart command in the host’s root-owned policy. Restart resets in-memory histories and may interrupt traffic: drain the host or schedule maintenance first. A failed ordinary reload never escalates to restart. Keep the correct Nginx service command in the policy; custom installations must update it before enabling module upgrades.

Deployment operations are journaled on both machines. A connection interruption produces unknown, not success. Reconciliation consults the host journal and restores a pre-change snapshot for interrupted activations rather than re-executing them. After recovery, inspect again before a new deployment. Configuration drift invalidates old previews. Serial rollouts stop at a failed or uncertain predecessor.

The helper’s status location is on a Unix socket inside its private managed directory. The native handler rejects TCP access and reports the release held in the worker’s memory. The helper also verifies the immutable module path mapped by that responding worker through Linux /proc. This distinguishes installed files from a loaded release. Successful verification checks a serving worker generation plus representative health probes; draining workers may still complete old requests after reload. The portal records the timestamp of verification, not a claim of continuous host monitoring.

REMOTE_TRANSPORT optionally selects the controller transport script path. The API container includes Python and OpenSSH; mount CREDENTIAL_KEY_FILE read-only into it and set the container path through a Compose override. Do not mount proxy configuration into the portal.