nettoolskit-access
v0.0.1-preview.1
Published
NetToolsKit Access operator CLI wrapper for npm and npx.
Maintainers
Readme
nettoolskit-access
Self-hosted Access VPS and control-plane stack: edge, remote access, observability, control, and backups on a single VPS.
Overview
nettoolskit-access is the public edge and remote-access node for the NetToolsKit infrastructure.
This stack provides:
Traefikas the central public HTTPS edge and route managerPortaineras the central Docker control planewg-easyfor the WireGuard tunnel and browser UIRustDeskfor self-hosted remote accessfail2banfor SSH protectionSeqas the lightweight logs, traces, and preview metrics surfaceOpenTelemetry Collectoras the vendor-neutral ingestion layer for Seqaccess-controlas the operator control surface for server, front-link, and remote-command operationsaccess-backupas the local backup job stack for Access state
The operating model is worker-first for runtime visibility and managed actions, with Portainer stack metadata and SSH kept only for host bootstrap/manual operations outside the control server:
- tracked Docker Compose templates live in
deployment/docker/ - shared deploy assets live in
deployment/shared/ - Vue/Quasar source and generated assets for the control server web UI live in
apps/access-control-ui/ - the Rust control server runtime that serves the UI and API lives in
crates/control/server/ - the Rust managed-server worker that connects outbound to the control server lives in
crates/control/workers/ - versioned shared runtime contracts live in
deployment/env/ - sensitive values may point to Bitwarden secrets
access-edgeis bootstrapped directly on the VPS because it owns Portaineraccess-traefikis applied by direct Compose because it owns the public route to Portainer; its containers shareCOMPOSE_PROJECT_NAME=nettoolskit-access- the remaining stacks are published to Portainer in rollout order
- CI/CD reuses the same deploy and smoke-test scripts as the operator flow
Control runtime organization:
server: the central Access control server hosts the Rust API and the embedded web frontendworkers: managed servers run the Rust worker outbound connector for near-real-time status and command execution without SSH polling
Runtime Model
Primary runtime contract:
Scoped env contracts used by Compose validation and Portainer publish:
deployment/env/edge.envdeployment/env/remote.envdeployment/env/observability.envdeployment/env/control.envdeployment/env/backup.env
Dedicated service env defaults:
Local non-versioned Bitwarden bootstrap:
.deployment/env/.env
Legacy bootstrap fallbacks still supported by the runtime helper:
.deployment/env/.env.bitwarden.temp/env/.env.bitwarden
Sensitive values should reference Bitwarden keys instead of storing plaintext
directly in the tracked runtime contract. The deploy flow resolves those
references before the stack is applied on the VPS. Only
BITWARDEN_ACCESS_TOKEN is expected outside the tracked runtime files.
Current access-specific secret references are grouped by application:
ACCESS_PORTAINERACCESS_TRAEFIKACCESS_WIREGUARDACCESS_RUSTDESKACCESS_VPSACCESS_SEQACCESS_OTELACCESS_BACKUPACCESS_CONTROLACCESS_GHCRfor Access-owned private GHCR pulls when needed- shared
NTK_GITHUB_CRinNetToolsKitfor cross-project private GHCR pulls
The runtime file now references grouped secret fields in the form
SECRET_NAME:FIELD_NAME, for example ACCESS_PORTAINER:ADMIN_PASSWORD.
Portainer automation tokens follow the same grouping rule and should use
ACCESS_PORTAINER:API_TOKEN, not a standalone token secret. API_TOKEN must
be an API token issued by Portainer for the automation/admin account; random
tokens are rejected by the Portainer API.
See more in scripts/runtime/README.md.
Service Surfaces
| Surface | Backing service or stack | Public entrypoint |
| --- | --- | --- |
| Portainer | access-edge / portainer | https://edge.access.nettoolskit.io |
| WireGuard UI | access-remote / wireguard | https://wireguard.access.nettoolskit.io |
| RustDesk | access-remote / hbbs + hbbr | rustdesk.access.nettoolskit.io:21115-21119/tcp, 21116/udp |
| Observability | access-observability / seq | https://observability.access.nettoolskit.io |
| Access control | access-control / control | https://control.access.nettoolskit.io |
| Traefik edge | access-traefik logical surface / traefik | public 80/443, loopback-only metrics 8082 |
| Backup jobs | access-backup / backup | no public UI |
The reverse-proxy routes are declared in deployment/shared/config/traefik/routes.json. Access Traefik is the route source of truth for Access, Quality, Copilot, and One public hostnames.
Quality administrative link targets are documented for later Access control
registration. The intended DNS names are sonar.quality.nettoolskit.io,
seq.quality.nettoolskit.io, otel.quality.nettoolskit.io, and
workers.quality.nettoolskit.io; seed activation, DNS, routing, TLS, and smoke
validation remain deferred to a later operator-approved slice targeting
QUALITY_VPS:HOST.
Stack Layout
Access stacks are organized by operational responsibility:
| Stack | Compose file | Role |
| --- | --- | --- |
| access-edge | deployment/docker/docker-compose.yaml | First stack. Owns the public edge, Portainer, and the shared Access edge network. |
| access-traefik | deployment/docker/docker-compose-traefik.yaml | Production Traefik edge on public HTTP/TLS with loopback-only metrics scraped by OTEL. Published by direct Compose to avoid depending on the route it owns; runtime containers keep the shared nettoolskit-access Compose project label. |
| access-remote | deployment/docker/docker-compose-remote.yaml | WireGuard, RustDesk (hbbs/hbbr), and fail2ban. |
| access-observability | deployment/docker/docker-compose-observability.yaml | Logs, traces, and preview metrics surface backed by Seq and OTEL Collector. |
| access-control | deployment/docker/docker-compose-control.yaml | Rust-backed central control server for server inventory, grouped front-link inventory, remote-client visibility, and allowlisted remote commands. |
| access-backup | deployment/docker/docker-compose-backup.yaml | Backup jobs and dry-run validation for Seq data and critical Access volumes. |
Container names use <service>-${COMPOSE_PROJECT_NAME}. With
COMPOSE_PROJECT_NAME=nettoolskit-access, the control container is
control-nettoolskit-access.
The shared Docker edge network is named separately with
ACCESS_EDGE_NETWORK_NAME so bootstrap runs that use a stack-specific Compose
project name still attach to the same external network.
The Access control runtime serves both the UI and the API from the same Rust
service. The frontend source under apps/access-control-ui uses Vue 3, Quasar,
Pinia, Vue Router, typed API services, and Vitest tests while preserving the
Rust artifact contract: dist/index.html, dist/login.html, and hashed assets
under dist/assets. The UI follows the same dark operator shell language as
Copilot Platform, but remains Access-owned and does not import Copilot source.
Access Control is the operator launcher and control surface; Seq is the current
logs/traces/metrics surface while status page is deferred.
The control login is enforced by the Rust backend. The tracked runtime contract
expects ACCESS_CONTROL_ADMIN_USERNAME and
ACCESS_CONTROL_ADMIN_PASSWORD to resolve from the ACCESS_CONTROL secret
group, using ADMIN_USERNAME and ADMIN_PASSWORD as the
grouped field names.
Worker Communication and Commands
Access control does not SSH into managed servers for inventory loading or operator actions. Managed servers initiate the connection to the central control server.
Connection direction:
managed server worker --outbound WSS/HTTPS 443--> access-control serverRuntime contract:
| Responsibility | Owner | Details |
| --- | --- | --- |
| Connection initiator | Worker on each managed server | The worker connects outbound to CONTROL_SERVER_URL; no inbound worker port is required. |
| Endpoint | Control server | /api/workers/connect over WebSocket, normally exposed as wss://<control-host>/api/workers/connect. |
| Authentication | Worker + control server | Worker sends Authorization: Bearer <CONTROL_WORKER_TOKEN>; the server rejects missing or invalid tokens. |
| Server identity | Worker | Worker sends CONTROL_WORKER_SERVER_ID, matching the server inventory record. |
| Telemetry | Worker -> server | Worker reports hostname, worker version, edge container name, and edge image state. |
| Commands | Server -> worker | Server sends typed command messages over the already-authenticated WebSocket. |
| Results | Worker -> server | Worker returns exitCode, stdout, and stderr; the server stores them in the action run history. |
Security model:
- The control server does not need
openssh-client, SSH keys, or an SSH bind mount for managed actions. - Managed servers do not need to expose SSH or any inbound control port for the worker channel.
- The worker token is configured server-side and worker-side only; it is never sent to the browser frontend.
- Commands are allowlisted by action name:
inspect-edge-agent,inspect-docker-version, andupdate-edge-agent. - The control UI/API cannot send arbitrary shell commands; the worker maps known action names to local handlers.
- Production traffic should use HTTPS/WSS through Access Traefik, with
CONTROL_SECURE_COOKIES=true. - The current token is shared for this first slice; the next hardening step is per-server tokens with rotation and revocation.
The control runtime sends browser security headers on API and HTML responses,
serves embedded HTML with a nonce-backed Content Security Policy, and defaults
session cookies to Secure, HttpOnly, and SameSite=Strict. Local HTTP-only
development can set CONTROL_SECURE_COOKIES=false; production should keep the
tracked true value because the public route is HTTPS-forced by Nginx Proxy
Manager.
The deploy flow backs up the critical Access volumes, starts access-edge
first as the direct bootstrap stack because it owns Portainer. That bootstrap
uses COMPOSE_PROJECT_NAME=nettoolskit-access as the direct Compose project so
container and volume suffixes stay stable. After Portainer is available, the
same deploy applies access-traefik by direct Compose because
Traefik owns the public Portainer route. The remaining access-remote,
access-observability, access-control, and access-backup stacks are
published through Portainer in rollout order.
Recommended public DNS records for the Access VPS:
| Purpose | Suggested host | Runtime key |
| --- | --- | --- |
| Wildcard | *.access.nettoolskit.io | DNS provider A/AAAA records |
| Portainer | edge.access.nettoolskit.io | EDGE_PUBLIC_HOST |
| WireGuard UI | wireguard.access.nettoolskit.io | WIREGUARD_PUBLIC_HOST |
| RustDesk host | rustdesk.access.nettoolskit.io | RUSTDESK_PUBLIC_HOST |
| Observability | observability.access.nettoolskit.io | OBSERVABILITY_PUBLIC_HOST |
| Access control UI | control.access.nettoolskit.io | ACCESS_CONTROL_PUBLIC_HOST |
Point the wildcard records to the same Access VPS public IP used by
NTK_VPS_HOST. The reverse proxy must only publish explicitly declared hosts;
unknown wildcard hostnames are expected to return a deny/404 response. Seq is
published behind TLS by the Access edge proxy; its
runtime secrets should come from ACCESS_SEQ. The current
observability stack receives OTLP on loopback-bound collector ports and forwards
logs, traces, and preview metrics to Seq. Public status page remains pending a
separate tool decision.
The Traefik stack exposes /ping and Prometheus metrics only on loopback for
deploy smoke and OTEL collection.
Access-owned Rust services use tracing for structured JSON logs on stderr.
access-control-server, access-control-worker, and access-backup include
stable fields such as service name, worker/server IDs, command IDs, action
names, and backup paths where applicable. Tune verbosity with RUST_LOG; the
Compose contracts expose CONTROL_RUST_LOG and BACKUP_RUST_LOG with info
as the default.
The control server also exports OTLP HTTP traces to the internal Collector when
CONTROL_OTEL_TRACES_ENABLED=true, using the private
http://otel-collector:4318/v1/traces endpoint on the Access Docker network.
The Access observability SLO and operator triage runbook is documented in docs/operations/access-observability-slo-runbook.md.
Quick Start
- Review
deployment/env/.envand the scoped env files underdeployment/env/. - Create
.deployment/env/.envwithBITWARDEN_ACCESS_TOKEN=..., or exportBITWARDEN_ACCESS_TOKENin the OS environment. - Run the deploy script.
- Run the smoke tests.
- Confirm the published routes in Access Traefik and the stack state in Portainer.
Create the Bitwarden bootstrap file:
New-Item -ItemType Directory -Path .\.deployment\env -Force | Out-Null
'BITWARDEN_ACCESS_TOKEN=replace-me' | Set-Content .\.deployment\env\.envDeploy from the local workstation:
pwsh -File .\scripts\deploy\deploy-vps.ps1Run the primary smoke tests from a nettoolskit-control checkout or installed
ntk-control binary:
cargo run --bin ntk-control -- smoke run --profile access --scope full --strict --timeout-ms 5000 --access-control-authBuild the Access control frontend after changing files under
apps/access-control-ui:
Set-Location .\apps\access-control-ui
npm install
npm run typecheck
npm test
npm run buildThe primary smoke test is owned by nettoolskit-control. It validates public
hosts, authenticated Access Control routes, and read-only VPS runtime state over
SSH. scripts/validate/test.ps1 remains only as a manual rollback fallback
until its deletion batch lands.
CI/CD is split between GitRiver and GitHub Actions. GitHub remains the source
of truth for code, pull requests, releases, and deploy intent. GitRiver runs
the expensive PR/runtime quality gates from metadata-only pipelines that clone
GitHub source at job runtime. The reusable GitRiver strategy for other
NetToolsKit repositories is documented in
deployment/shared/config/ci/README.md.
River quality gates validate:
- Compose rendering for Access runtime stacks
- runtime contract checks and changed-surface routing
- changelog governance for runtime-affecting changes
- source-gate status and failure-issue wrapper behavior
- GitHub Packages readiness for generated Access images targeting
ghcr.io/nettoolskit - Rust test/security checks for affected source surfaces
- PowerShell parser validity for deploy/runtime/validation scripts
- Docker image version drift as an advisory River status context for image and compose surfaces
- external GitHub commit statuses that link back to the exact River pipeline and job
GitHub Actions stays intentionally narrow. It owns only production promotion work that still depends on GitHub-native release/package permissions:
- selected GHCR image publication for only the affected owned Access images
- live VPS smoke checks after deploy, with scoped smoke when the changed surface is narrow
- deploy tags and releases
Workflow triggers are intentionally scoped to reduce Actions usage:
- PR runtime tests, changelog enforcement, package checks, vulnerability checks, Docker image drift checks, and variable-quality validations belong in River.
- GitRiver starts from visible PR and main triggers; repository-owned
changed-surface gates publish
passed,failed, orskippedso README, docs, planning, and unrelated reference-only PRs keep status visibility without running expensive work. - River jobs verify
GITHUB_SOURCE_SHAafter cloning the GitHub branch and detach to the exact commit when the shallow branch checkout is stale. - GitHub validation workflows are not present; PR signal comes from external River status contexts.
maindeploys run only for runtime-affecting deploy paths.- local operator tooling under
crates/tools/**is validated by River when it is in the changed source surface, but does not trigger production deploy by itself. - GHCR image publication runs on
mainonly when generated image inputs change, and publishesaccess-control,access-control-worker, oraccess-backupindependently. access-control-workerimage-only changes publish the worker image without redeploying the Access VPS because that image is consumed by managed hosts.- deploy snapshot tags are created only by the deploy workflow after the VPS deploy succeeds and smoke tests pass or are intentionally skipped.
- GitRiver metadata-only changes are validated by River and do not redeploy the VPS after merge.
Manual production deploys are available from GitHub Actions after the workflow
is present on main: open Actions, select Deploy access stack, choose Run
workflow, keep the branch as main, and set the inputs:
publish_images=auto: manual default; publish all owned images.publish_images=alloralways: force all owned image publication.publish_images=noneornever: skip image publication.publish_images=control,worker, orbackup: publish one owned image.deploy_stack=always: manual default; deploy the VPS stack.deploy_stack=never: publish selected images without deploying.deploy_stack=auto: deploy only when the selected surface needs a VPS change.smoke_scope=auto: run full smoke for broad/manual deploys and scoped smoke for narrow control or backup image deploys.
Equivalent GitHub CLI command:
gh workflow run deploy-access.yml --ref main -f publish_images=auto -f deploy_stack=always -f smoke_scope=auto
gh run list --workflow deploy-access.yml --branch main --limit 5Image Publishing
Owned Access runtime images are generated from the catalog at
deployment/images/access-images.toml:
ghcr.io/nettoolskit/access-controlghcr.io/nettoolskit/access-control-workerghcr.io/nettoolskit/access-backup
External images remain pinned in env/Compose contracts and are not generated by
this repository. The catalog lists Portainer, Traefik, wg-easy,
RustDesk, OTEL Collector, Seq, fail2ban, and
the one-shot alpine operational probe base as external images.
Repository-owned long-running services become Docker images. Operator commands and bootstrap helpers should become installable Rust CLI commands instead of images.
The publisher CLI lives at crates/tools/access-image-publisher and reads the
catalog to compute Docker buildx commands and tags. The operator CLI
crates/tools/accessctl wraps the same image commands and also exposes local
backup commands for Linux installs. Rust crates are part of a root Cargo
workspace with a single checked-in Cargo.lock, so local builds, Docker
builds, and installable CLI builds resolve the same dependency graph.
Local generation loads images into the local Docker daemon and also tags local aliases from the catalog:
cargo run --manifest-path .\crates\tools\access-image-publisher\Cargo.toml -- plan
cargo run --manifest-path .\crates\tools\access-image-publisher\Cargo.toml -- build --dry-run
cargo run --manifest-path .\crates\tools\access-image-publisher\Cargo.toml -- buildEquivalent accessctl commands:
cargo install --path .\crates\tools\accessctl --locked
cargo run --manifest-path .\crates\tools\accessctl\Cargo.toml -- images --repo-root . plan
cargo run --manifest-path .\crates\tools\accessctl\Cargo.toml -- images --repo-root . build --dry-run
cargo run --manifest-path .\crates\tools\accessctl\Cargo.toml -- backup dry-run --source-root .\.temp\accessctl-backup-source --target-root .\.temp\accessctl-backup-output
cargo run --manifest-path .\crates\tools\accessctl\Cargo.toml -- validate compose --repo-root . --compose-file deployment/docker/docker-compose-backup.yaml
cargo run --manifest-path .\crates\tools\accessctl\Cargo.toml -- validate public-ports --repo-root .
cargo run --manifest-path .\crates\tools\accessctl\Cargo.toml -- validate image-versions --repo-root . --catalog deployment/images/access-images.toml --warning-onlyLinux hosts can install the same CLI directly from Git:
cargo install --git https://github.com/NetToolsKit/nettoolskit-access.git accessctl --lockedLocal prerelease operator package:
cargo install --path .\crates\tools\accessctl --locked --root .\.build\ntk-access-v0.0.1-preview.1 --force
.\.build\ntk-access-v0.0.1-preview.1\bin\ntk-access.exe --version
.\.build\ntk-access-v0.0.1-preview.1\bin\ntk-access.exe images --repo-root . build --dry-run
.\.build\ntk-access-v0.0.1-preview.1\bin\ntk-access.exe images --repo-root . publish --dry-runLocal build aliases:
access-control:localaccess-control-worker:localaccess-backup:local
Generated image runtimes are intentionally minimal. The Rust services build in
digest-pinned toolchain stages, then run from digest-pinned distroless
base-nossl-debian12 final images with no package manager and no shell.
Release builds strip symbols, use thin LTO, and abort panics. Current local
image sizes are approximately:
access-control:local: 31 MBaccess-control-worker:local: 89 MBaccess-backup:local: 26 MB
access-control runs non-root and binds to port 8080 inside the container.
access-control-worker and access-backup keep root runtime users for now:
the worker mounts /var/run/docker.sock, which is root-equivalent on managed
hosts, and the backup runner must read/write Docker volumes owned by other
containers. The worker image copies only the Docker CLI binary instead of
installing the full docker.io package.
access-backup is performance-first by default: it keeps .tar.gz
compatibility, uses gzip level 1 unless overridden, and archives independent
source volumes with bounded parallelism. Tune with
BACKUP_COMPRESSION_LEVEL=0..9 and BACKUP_MAX_PARALLELISM=<n>.
Run Compose with the local control image by overriding CONTROL_IMAGE:
$env:CONTROL_IMAGE = 'access-control:local'
docker compose -f .\deployment\docker\docker-compose-control.yaml --env-file .\deployment\env\control.env configPublish to GHCR only after Docker is authenticated:
cargo run --manifest-path .\crates\tools\access-image-publisher\Cargo.toml -- plan --format json
cargo run --manifest-path .\crates\tools\access-image-publisher\Cargo.toml -- publish --dry-run
cargo run --manifest-path .\crates\tools\access-image-publisher\Cargo.toml -- publishTag rules:
- immutable commit tag:
<short-sha> - deploy snapshot tag:
access-<yyyymmdd>-<short-sha> - branch tag for non-main builds
latestonly for the defaultmainbranch- local aliases only during
build, never duringpublish
GitHub Actions publishes selected owned images with GITHUB_TOKEN and
packages: write. Production deploy receives immutable snapshot tags only for
images published in the current run. ACCESS_CONTROL_IMAGE overrides
CONTROL_IMAGE, ACCESS_CONTROL_WORKER_IMAGE is available for managed-host
worker publishes, and ACCESS_BACKUP_IMAGE overrides BACKUP_IMAGE during
the Portainer publish. CI deploys pass the workflow's
ephemeral GITHUB_TOKEN to the remote Docker login path with packages: read
so private same-repository GHCR packages can be pulled by the VPS. For manual
deploys outside GitHub Actions, add GHCR_USERNAME and GHCR_TOKEN to the
relevant scoped env contract and resolve them from a Bitwarden group such as
ACCESS_GHCR:USER and ACCESS_GHCR:TOKEN. Cross-project stacks should prefer
the shared NetToolsKit project with NTK_GITHUB_CR:USER and
NTK_GITHUB_CR:TOKEN, declared through sharedBitwardenProjects in the
Portainer metadata instead of duplicating the token in every project.
GitRiver validates package readiness in river/package before
publication. That lane packages the Rust workspace, generates the Access image
plan from deployment/images/access-images.toml, and dry-runs the publish
commands that target GitHub Packages at ghcr.io/nettoolskit. It does not push
images; mutating publication still requires an explicit write-scoped package
credential and release policy.
The first installable CLI target is accessctl. It already covers image
planning/build/publish, local backup run/dry-run, and deterministic local
validation for Compose and the Access image catalog. Existing validation
scripts remain as transition surfaces until their Rust parity commands have
local evidence, CI adoption when relevant, and remote smoke coverage when the
script talks to deployed infrastructure. New reusable operator commands should
live in the distributed repositories instead of growing accessctl: deploy,
Portainer, proxy, Traefik, compose, backup, and image-catalog operations belong
in nettoolskit-devops, while live smoke, machine control, worker, and
RustDesk operator flows belong in nettoolskit-control. Access should keep
only Access-local entry points and configuration contracts while those
replacements mature. Those commands are not Docker image candidates unless they
become long-running services.
Publishing the CLI through a registry such as crates.io remains a release
decision because it requires a public license/registry policy. The manifests
already use versioned path dependencies so the crate split is ready for that
step once the policy is chosen.
Access Traefik
Access Traefik is the central public gateway. It terminates TLS, applies route policy, and forwards to Access, Quality, Copilot, and One upstreams.
Portainer keeps its own admin account and password. The deploy flow also synchronizes the configured Portainer username after the initial bootstrap, so the intended operator account can be [email protected] instead of the default admin.
Seq keeps the observability admin account inside its own data volume. Store
PUBLIC_HOST, FIRSTRUN_ADMINPASSWORD, FIRSTRUN_ADMINPASSWORDHASH,
STORAGE_SECRETKEY, and SERVER_URL in ACCESS_SEQ. The
plain first-run password is kept for operator records and hash rotation only;
the active Compose contract injects the hash and storage key, not the plaintext
password. The deploy flow does not create status-page, monitor, metric, or
dashboard resources in this slice.
The public proxy hosts and Let's Encrypt certificate state are owned by the tracked Traefik route manifest:
The hostnames consumed by that manifest should come from Bitwarden-backed runtime values instead of being hardcoded in tracked files. Access Traefik owns certificate creation and reuse for the current Access edge. The previous Nginx Proxy Manager and certbot/webroot flows are no longer active.
See more in scripts/deploy/README.md.
Repository Layout
Cargo.toml
Cargo.lock
deployment/
├── README.md
├── docker/
│ ├── docker-compose.yaml
│ ├── docker-compose-remote.yaml
│ ├── docker-compose-observability.yaml
│ ├── docker-compose-backup.yaml
│ ├── docker-compose-traefik.yaml
│ └── docker-compose-control.yaml
├── shared/
│ ├── config/
│ │ ├── fail2ban/
│ │ ├── traefik/
│ │ └── observability/
│ │ └── seq/
│ └── portainer/
│ └── stacks/
├── images/
│ └── access-images.toml
└── env/
├── .env
├── edge.env
├── remote.env
├── observability.env
├── backup.env
├── control.env
├── wireguard.service.env
└── fail2ban.service.env
apps/
└── access-control-ui/
crates/
├── backup/
│ └── runner/
├── control/
│ ├── server/
│ └── workers/
│ └── agent/
└── tools/
├── access-image-publisher/
└── accessctl/
scripts/
├── README.md
├── deploy/
├── operations/
├── validate/
├── runtime/
└── integrations/
tests/
└── README.mdSee more in scripts/README.md.
Documentation
scripts/README.md— script index and execution entry pointsscripts/operations/test-access-live-preflight.ps1— read-only preflight before Access live apply/evidence windowsscripts/deploy/README.md— deploy flow and central Traefik route/certificate syncscripts/runtime/README.md— runtime and Bitwarden resolution modelscripts/validate/README.md— smoke-test flow- docs/operations/access-observability-slo-runbook.md — Access observability SLO, SLI, Seq preview, and live-evidence runbook
scripts/integrations/portainer/README.md— Portainer diagnostic helpersscripts/integrations/rustdesk/README.md— RustDesk client templates and helperCHANGELOG.md— runtime and deployment change log for governed Access releases
Technical References
npm and npx
This repository exposes the ntk-access operator command through the nettoolskit-access npm package for local installation and npx execution.
npm install -g nettoolskit-access
ntk-access --help
npx nettoolskit-access --helpThe npm wrapper executes a native ntk-access binary from npm/native/ when release packaging stages one. For development or private release validation, set NTK_ACCESS_BINARY to an already built local binary. Use npm run stage:native -- <path-to-binary> before packaging a native tarball.
Cargo package names use the nettoolskit-access-* prefix. The existing operational binaries such as accessctl, access-backup, and access-image-publisher remain declared as Cargo bin aliases where needed so current deploy and CI paths are not broken by package renaming.
