← All utilities

NSGateway

Version 26.1 (build 508) View the PPT
NSGateway
Contents

What NSGateway is

nsgateway is Nacarsoft’s connection gateway: a single binary that brings together the web terminal, SSH, reverse proxy, public sites by Host and public portals. It replaces direct SSH access, bastion hosts and tunnels: the user signs in over HTTPS with their identity and role, the administrator decides which applications and targets are published, and every session is recorded.

  • Four access modes: terminal application (server command), SSH application (host/port), proxy application (internal URL) and public or private portal (catalogue with optional sign-in and limits).
  • No clients on the desk: no SSH client, keys or tunnels. HTTPS and WebSocket only.
  • Central identity: JWT, users and groups, per-application RBAC, session quotas and optional LDAP/Active Directory.
  • Internal consoles: published through the reverse proxy with an allowlist, private-IP/cloud-metadata blocking and link rewriting.
  • Public and private portals: for vendors, on-call teams, external support or internal users; public ones are anonymous and private ones require signing in, both with limits and auditing.
  • Public sites by Host (Caddy-style): independent sites stored in SQLite, routed by Host and path, with proxy or redirect routes, strip_prefix, header rules, gzip/zstd, per-site JSONL access logs and a read-only Caddyfile preview. TLS terminates in front; sites are public by design.
  • Sessions and audit: app, user, PID, origin portal, IP, country, browser, children, CPU/memory, timeout and kill reason; search and filters by user, app and portal, and sorting by any column; startup/periodic reconciliation closes dead rows and kills verified orphan process groups without touching recycled PIDs.
  • Web experience: templates with header/side panels/status bar, availability schedules, Natural PF keys, themes and languages.
  • A single binary with embedded SQLite; REST API for automation.

Commands, applications, hosts and users in the examples are fictional.

Connections to NSGateway: browser, tablet and phone come in over HTTPS; NSGateway concentrates access to servers, SSH, internal applications and public portals

Use cases

1. Concentrate access to servers and SSH

Publish a shell and an SSH server without installing clients or handing out keys.

nsgateway init /tmp/nsgateway-demo
# → prints the random admin password; keep it
nsgateway start --config /tmp/nsgateway-demo
nsgateway status --config /tmp/nsgateway-demo
# → NSGateway v26.1 ... Listening: http://0.0.0.0:11030

Web flow: Administration → Applications → create a terminal app (shell, command /bin/bash) and an SSH app (host, port 22, authentication password or system) → assign them to groups → Dashboard → Open.

2. Publish internal consoles through the proxy

Expose an internal web application without opening its URL to the user network.

Web flow: Administration → Applications → Proxy URL type (targetUrl https://intranet.example.local:8443/app, WebSocket enabled if the app uses it, link rewriting) → assign to groups. Only the administrator defines the URL; the user opens it with their session, RBAC and audit.

3. Publish a whole site by Host (Caddy-style)

Give erp.example.com its own routes without writing a Caddyfile.

Web flow: Administration → Sites → create the site (host, compression and access-log file) → add /api/* as a proxy route to the erp-api application with strip_prefix, and /old as a redirect to /new with status 301. TLS terminates in front (nginx, Caddy or a load balancer); NSGateway receives HTTP, routes by Host and path, compresses, rewrites headers, writes JSONL access logs under logs/sites/ and shows the read-only equivalent Caddyfile. Sites are public: the WAF, rate limits, IP blocklist and SSRF guardrails still apply, but login/RBAC do not.

4. Open a public portal for vendors or on-call teams

Give anonymous, scoped access to an application catalogue.

Web flow: Administration → Portals → create (slug, name, description, template and sessionTimeout) → add public applications → share https://gateway.example.local/pub/<slug>. The portal does not ask for login, applies per-IP and time limits, and sessions are tagged public.

5. Give a team limited access with a quota

The operators group can use prod-console with a maximum of 2 concurrent sessions per user.

Web flow: Users → create user → assign the group → Groups → assign the application with its per-user max → the user only sees their applications; past the quota they get the notice and no new session opens.

6. Monitor and kill sessions

See who runs what, from where and at what cost.

Web flow: Sessions (app, user, PID, start, duration, timeout, CPU, memory, IP, country, browser, children; filters by active/closed/all, origin, type, user, app, portal and IP; sort by column) → kill a session with a reason, or bulk-kill by selection/IP/portal/app. With the admin role, HTTP/HTTPS connections and the RX/TX chart are shown too.

7. Give an application a web look and a schedule

Turn a terminal application into a console with a corporate header, side menu, status bar and PF keys.

Web flow: Administration → Templates → assign to the application; Schedules → availability template (morning, afternoon, night, weekend or workday); outside its window the app shows as Closed and the server refuses to open it. Administrators are also subject unless explicitly exempted.

8. Integrate LDAP/AD and invitation-based sign-up

Use the corporate directory without losing local users.

Web flow: Configuration → Authentication → LDAP (URLs, base DN, bind, filters and attributes) → test connection. For sign-up: Authorizations → enable self sign-up, default group, activation mode and authorized email list (or import CSV) → send an individual or bulk invitation.

9. Automate and audit with the API

Query applications and sessions from a script with the session cookie.

# After signing in on the web, reuse the session cookie
curl -b cookie.txt http://localhost:11030/api/apps
curl -b cookie.txt "http://localhost:11030/api/sessions?status=active"

Web flow: Audit → filter by time, user, action, detail, IP and country; sign-ups, group changes, accesses and kills are recorded.

Interface

NSGateway dashboard: published applications and a summary of active sessions

Active sessions with user, PID, duration, IP and usage

AreaWhat it does
DashboardAvailable applications and a summary of active sessions
TerminalsTabs per session, reconnection, disconnect, full screen and HTML mirror
SessionsLive list, filters, timeout, CPU/memory, children and kill with reason
ApplicationsCreate and edit terminal, SSH and proxy apps
SitesPublic sites by Host: proxy/redirect routes, compression, headers and JSONL logs
PortalsPublic or private catalogue with template, apps, limits and anonymous per-IP quota
UsersCreate, alias, email, state, groups and Linux user
GroupsRole, assigned applications and per-user session quota
TemplatesHeader, side panels and status bar with HTML/CSS, corporate logo and PF
SchedulesAvailability windows per day, with timezone and several windows
AuthorizationsAuthorized emails, invitations, self sign-up and approvals
ConfigurationAppearance, authentication, LDAP, branding, proxy, HTTPS and server
AuditSearch by time, user, action, detail, IP and country
Login and profileAccess, password recovery, themes and language

Languages: ES and EN. Themes: dark, light and high contrast, with font sizing.

Reference

Requirements

RequirementDetail
SystemLinux (tested on RHEL 8/9 and Debian)
BinaryA single one, with embedded SQLite
Port11030 by default, configurable
Reverse proxyOptional: terminates TLS and forwards to NSGateway, or use the built-in HTTPS
SSHNot needed for user access
LicenseMachine-signed; license shows status and fingerprint
BrowserModern browser; nothing to install on the desk

CLI commands

CommandDescription
nsgateway init [dir]Creates config.yaml, the SQLite database and logs/, and prints the random admin password. Fails if config.yaml already exists
nsgateway start [dir]Starts the server in the background (daemon)
nsgateway stopStops the server
nsgateway restart [dir]Restarts the server (stops it if running, then starts it again)
nsgateway statusStatus, PID and listen address
nsgateway run [dir]Foreground server (for systemd; no daemonizing)
nsgateway license [dir]License status and machine fingerprint
nsgateway version (--version, -v)Version and build
--config <dir>Environment directory; also accepted as a positional argument
--port NOverrides the configured port
--debugDebug mode

The current binary and documentation are nsgateway.

Main configuration (config.yaml)

KeyDescription
server.host / server.portListen address (default 0.0.0.0:11030)
server.tls.enabled / modeBuilt-in HTTPS: files, selfsigned or acme
server.tls.certFile / keyFile / domains / email / cacheDirCertificates, domains and TLS cache
server.tls.httpPort / redirectHttpHTTP listener and 301 redirect to HTTPS
database.pathState SQLite (./db/nsgateway.db)
auth.jwtSecret / jwtExpiryMin / cookieNameJWT session (nsgateway_session, 480 min by default)
auth.passwordMinLength / passwordRequireLetters / passwordRequireDigits / passwordRequireSymbolsPassword policy
auth.passwordExpiryDays / passwordExpiryWarnDays / passwordExpiryAwayDays / passwordHistoryCountExpiry, warnings and history
auth.ldap.*Optional LDAP/AD: URLs, base DN, bind, filters, attributes and default group
smtp.*Outgoing mail (smtp/sendmail, security and sender)
registration.*Self sign-up: enablement, default group, approval and validity
server.allowedHosts / server.trustedProxiesHost allowlist (include the public site Hosts) and proxy CIDRs whose X-Forwarded-* is trusted
proxy.allowedHosts / blockPrivateIPs / blockMetadataIPSSRF guardrails for proxy apps
proxy.upstreamMaxIdlePerHost / upstreamMaxConns / upstreamIdleTimeoutSecKeep-alive pool and backend connection caps
proxy.compression / breakerEnabled / breakerFailures / breakerCooldownSecgzip for text responses and per-app circuit breaker
proxy.upstreamCAFile / upstreamCertFile / upstreamKeyFile / upstreamServerName / upstreamInsecureSkipVerifyPrivate CA, mutual TLS and SNI override for HTTPS backends
proxy.maxBodyMB / maxRequestBodyMB / responseTimeoutSec / idleTimeoutSecRewrite body cap, upload cap, response timeout and idle proxy-session timeout
security.*WAF, rate limits, blocklist and notifications (see Edge security)
branding.companyName / logoUrl / customLoginCorporate identity and custom login
logging.*Directory, size, retention, backups and compression

NSGateway refuses to start with an empty or example jwtSecret. Use openssl rand -hex 32.

The license is looked up at $NS_HOME/licenses/nsgateway.key (NSGateway’s license identifier). NS_HOME defaults to /opt/ns.

Application types

FieldDescription
appId / name / descriptionIdentifier and visible texts
typeterminal (server command), ssh (host/port) or proxy (internal URL)
command / args / workingDir / envCommand, arguments, directory and environment (terminal)
timeoutSession timeout (1d3h4m8s); empty = no limit
sshHost / sshPort / sshAuthSSH target and authentication (password or system)
sshCommandOptional remote command executed after login (empty = interactive shell)
runAsMode / runAsFixed system user or the connected user’s Linux account
cols / rows / maxCols / maxRowsTerminal geometry or fit-to-container with caps
targetUrl / proxyWs / proxyRewriteInternal URL, WebSocket and link rewriting (proxy)
templateId / scheduleId / pfKeysTemplate, schedule and PF keys
openInTab / htmlView / allowAppearance / isActiveBrowser tab, HTML mirror, appearance and state

Notes:

  • SSH: password authentication uses an SSH client embedded in the binary (no sshpass); system authentication uses OpenSSH with its keys and agent. The visitor enters username and password in the form; the password travels over the encrypted WebSocket, is used only in memory and is never stored. The client runs as the service user (it ignores run_as and sudo); the first connection stores the server key in known_hosts (accept-new). The sshCommand field runs a remote command after login (for example cd /opt/app && ./start.sh); empty opens the shell.
  • Proxy: the user never types the URL; only the administrator defines it. allowedHosts restricts targets and blockPrivateIPs / blockMetadataIP add SSRF protection.
  • Quotas: the per-group, per-application maxUserSessions wins over the application default (maxUserSessions); the group is the authority for its members, and an explicit 0 means unlimited. /api/apps/usage reports both max and limitSource (group or app). Past the quota no new session opens.

Reverse proxy data plane and operations

The proxy is tuned by default: a keep-alive pool of 200 sockets per backend, gzip for HTML/CSS/JS/JSON/SVG, a per-app circuit breaker (5 failures, 15 s cooldown), private CA / mutual TLS / SNI override for HTTPS backends, an upload cap and a response timeout. Edit them in Administration → Configuration → Proxy.

EndpointUse
GET /healthzLiveness: 200 while the process runs
GET /readyzReadiness: checks SQLite; 503 when unavailable
GET /metricsPrometheus text: requests, latency histogram, proxy errors, circuit-breaker rejects, goroutines, memory and SQLite pool
GET /debug/pprof/Go profiles

/metrics and /debug/pprof only answer from loopback or the addresses in server.trustedProxies; they are never public. SIGTERM performs a graceful shutdown: stop accepting connections, drain in-flight requests for up to 25 seconds and close SQLite afterwards (allow TimeoutStopSec=40 and LimitNOFILE=1048576 in the service manager). SQLite runs in WAL with synchronous=NORMAL, a 25-connection pool and a 10 s busy timeout; proxy heartbeats are coalesced to one write per session every 30 s.

Public sites by Host (Caddy-style)

In addition to embedded proxy apps, NSGateway publishes independent sites by Host, with semantics close to Caddyfile blocks but stored in SQLite. TLS terminates in front (nginx, Caddy, a load balancer): NSGateway listens on HTTP and routes by Host and path. Administration → Sites.

Site fields: name and description (labels), host (exact or *.example.com; empty = host-less fallback only), encode (gzip, zstd, gzip,zstd or empty), log_file, enabled.

Route fieldDescription
match_path/* (all), /api/* (prefix) or /health (exact); the most specific route wins
actionproxy (to an existing proxy app) or redirect
app_idProxy app whose target_url is the upstream (not duplicated on the site)
strip_prefixhandle_path equivalent: strips the prefix before the backend
preserve_hostKeeps the original Host or sends the upstream host
redirect_to / redirect_statusTarget ({uri}, {path}, {query}) and 301/302/303/307/308
request_headers / response_headersJSON {"set":{...},"remove":[...]}; hop-by-hop and Host/Content-Length are rejected
log_fileRoute-specific log (empty = site log)
keep_queryKeeps the query string on redirects

Example equivalent to a Caddy block:

erp.example.com {
    encode gzip zstd
    log { output file erp.log }
    handle_path /api/* { reverse_proxy app:erp-api }
    redir /old /new permanent
}

In practice: create the site erp.example.com, a /api/* proxy route to the erp-api app with strip_prefix, and an /old redirect route to /new with status 301. The Caddyfile tab shows the read-only equivalent.

Resolution order: exact-host site → wildcard-host site → host-less routes (only from NoRoute, so /api, /login, /static and the admin pages stay owned by NSGateway) → normal NSGateway routes. If a Host belongs to a site but no route matches, that site’s 404 is returned. Do not create a site for the NSGateway administration Host.

Logs: logs/sites/<file> in JSON Lines (ts, site, route, app, remote_ip, host, method, uri, proto, status, bytes, duration_ms, user_agent, referer, upstream, error) with the normal rotation settings. Absolute paths and .. are rejected.

Security: sites are public and bypass login/RBAC; the UI warns. WAF, rate limits, the IP blocklist, host allowlist and SSRF guardrails still apply because routing runs after the security guard. If server.allowedHosts is set, include the public site Hosts. A disabled app returns 503; an app used by a site cannot be deleted (409). This version has no own TLS/ACME, static files, basic_auth or load balancing.

API: GET/POST /api/admin/sites, GET/PUT/DELETE /api/admin/sites/:id (with the routes nested in the site payload).

Public and private portals

A portal publishes an application catalogue for vendors, on-call teams, external support or internal users:

  • Created in Administration → Portals with slug, name, description, template, visibility and sessionTimeout.
  • Public: /pub/<slug> requires no account and lists the active applications of the portal.
  • Private: authentication is required; anonymous visitors go to the login page and return to the portal. Only the applications the user may open through their groups are shown.
  • Only public portals grant anonymous access: an application that belongs only to a private portal is not served at /public/<appId>.
  • Each card shows the limits; in anonymous mode the per-user quota is applied per IP address.
  • Anonymous sessions are tagged public and audited like user sessions.

Templates, schedules and PF keys

  • Templates: header, left/right container and status bar with HTML/CSS; CSS is isolated in a shadow root. Placeholders such as {{app.name}}, {{user.name}}, {{company.name}}, {{company.logo}}, {{pf.buttons}} and live values ({{now.time}}, {{session.uptime}}, {{session.remaining}}). They can be exported and imported as JSON (with preview and skip/overwrite mode). In a portal, the session values follow the selected SSH or terminal tab.
  • Schedules: morning, afternoon, night, weekend and workday templates; own timezone, several windows and midnight crossing. The server is the authority: outside the window the app shows as Closed and cannot be opened.
  • PF keys: the application declares PF1..PF12 and the template renders the buttons; pressing one sends the sequence to the session (Natural or xterm codes depending on the app).
  • Branding: corporate name and logo in templates and, optionally, on the login screen.

Sessions and auditing

Every session records application, user, PID, start, duration, timeout, CPU, memory, IP, country, browser and children. The list updates live over WebSocket and allows:

  • Filtering by active/closed/all, origin (public/user), type (terminal/ssh/proxy), portal, application or IP.
  • Killing a session (with a reason) or bulk-killing by selection, IP, portal or application.
  • Adjusting the timeout of a specific session.
  • With the admin role, viewing HTTP/HTTPS connections and RX/TX traffic.
  • Proxy sessions show a “Session ended” overlay; terminal/SSH sessions show the reason.
  • Reconciliation: at startup and every 15 s NSGateway closes rows whose process is gone, ignores recycled PIDs (it never signals an unrelated process) and kills verified orphan process groups left by a crash; proxy rows follow heartbeats and the proxy sweeper. These actions are audited (session_reconcile_*).

Edge security and notifications

NSGateway can be exposed directly to the Internet with:

  • WAF in monitor or block mode, global/per-IP rate limiting, concurrency and WebSocket limits.
  • Persistent IPv4/IPv6/CIDR blocklist, manual and automatic, with an allowlist.
  • Host validation, header limits, timeouts and connection caps.
  • Events and metrics in memory and logs/security/*.jsonl; SQLite only stores configuration, RBAC, sessions and the blocklist.
  • Administration → Security page (/security) with live events, incidents, blocked IPs and email notification settings.
security:
  waf:
    enabled: true
    mode: monitor          # monitor | block
  ipBlock:
    enabled: true
    auto: true
    threshold: 30
    allowlist: []
  limits:
    globalPerSecond: 20000
    perIPPerSecond: 300
    perIPBurst: 600
    perIPConcurrent: 2000
    proxyPerIPPerSecond: 600
    userPerSecond: 60
    userBurst: 240
    userConcurrent: 120
  notifications:
    enabled: false
    recipients: []
    minSeverity: high
    cooldownMinutes: 15
    maxPerHour: 30
    digestMinutes: 0

Notifications include severity threshold, categories, cooldown, hourly cap, digest and quiet hours. One email is sent per grouped incident, not per request. Authenticated requests skip the per-IP bucket and use the user* budget instead, so a corporate NAT or VPN with hundreds of users is not throttled as one offender; anonymous floods remain capped per address.

API

Method and pathDescription
GET /api/versionVersion and fingerprint
POST /api/auth/themeChange the theme
GET /api/auth/meCurrent user, role and groups
POST /api/auth/passwordChange password
GET /api/apps / GET /api/apps/usageVisible applications and usage (max, limitSource: group or app)
GET /api/terminal/:appId/checkPre-open check (quota, active app)
GET /api/terminal/:appId/check?resume=<id>Check before resuming a running session
GET /api/terminal/:appId/wsTerminal WebSocket
GET /api/terminal/:appId/ws?resume=<id>WebSocket reconnecting to an existing session
GET /api/proxy/:appId/*pathReverse proxy for the internal application
POST /api/proxy-session/open/:appIdOpen a proxy session
GET /api/sessionsSessions (status, origin, type, portal, app, user, ip, q, sort, dir, from, to, limit, offset)
GET /api/sessions/filtersDistinct users, applications and portals for the filters
DELETE /api/admin/sessions/:idKill a session (reason, force)
POST /api/admin/sessions/bulk-killBulk kill by ids, ip, portal or app
PUT /api/admin/sessions/:id/timeoutExtend or shorten a session
POST /api/registerSign-up with an invitation token (public)
GET /api/systemSystem status
GET/POST/PUT/DELETE /api/admin/*Users, groups, roles, apps, portals, audit and configuration
GET/POST /api/admin/sites · GET/PUT/DELETE /api/admin/sites/:idPublic sites by Host with nested routes
GET/POST/PUT/DELETE /api/admin/registrationsAuthorized emails and invitations
GET /healthz · GET /readyzLiveness and readiness (SQLite)
GET /metrics · GET /debug/pprof/*Prometheus metrics and Go profiles (loopback / trustedProxies only)
# With the web session cookie
curl -b cookie.txt http://localhost:11030/api/apps
curl -b cookie.txt "http://localhost:11030/api/sessions?status=active"

# Pre-open check for a terminal app
curl -b cookie.txt http://localhost:11030/api/terminal/shell/check

Security and license

  • HS256 JWT login in an HttpOnly cookie with configurable expiry.
  • Argon2id passwords (legacy bcrypt hashes are upgraded on next login), with length policy, expiry, warning and history.
  • Optional LDAP/Active Directory, coexisting with local users.
  • SSRF protection in the proxy: allowlist, private-IP and cloud-metadata blocking, body limit and timeout.
  • Public sites by Host bypass login/RBAC by design; the WAF, rate limits, blocklist, host allowlist and SSRF guardrails still run before their routes.
  • Audit of accesses, sign-ups, group changes, kills, site changes and administrative actions.
  • Machine-signed license at $NS_HOME/licenses/nsgateway.key. Without a valid license the service does not start; license shows the fingerprint to request one.

Commented examples

# 1. New environment and startup
nsgateway init /opt/nsgateway
# save the admin password printed by init
nsgateway start --config /opt/nsgateway
nsgateway status --config /opt/nsgateway

# 2. Restart after changing config.yaml
nsgateway restart --config /opt/nsgateway

# 3. License and version
nsgateway license --config /opt/nsgateway
nsgateway version

# 4. Foreground for systemd
nsgateway run --config /opt/nsgateway

Reverse proxy with nginx (WebSocket included):

server {
    listen 443 ssl;
    server_name gateway.example.local;

    ssl_certificate     /etc/pki/tls/certs/gateway.crt;
    ssl_certificate_key /etc/pki/tls/private/gateway.key;

    location / {
        proxy_pass         http://127.0.0.1:11030;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection "upgrade";
        proxy_set_header   Host $host;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
        proxy_read_timeout 3600s;
    }
}

FAQ

What is the difference between NSGateway and a web terminal? NSGateway is the gateway: besides the web terminal, it publishes SSH applications, internal applications through the proxy and public portals, all with the same identity, RBAC and audit.

Does it replace SSH? Yes for the user: no client to install and no keys to manage. It can also publish SSH applications against existing servers; the OpenSSH client runs on the NSGateway server.

Do I need to open port 22? Not for user access. Only HTTPS (and WebSocket) on 11030 is needed; if SSH apps are published, NSGateway makes an outbound connection to the configured host/port.

What is the initial admin password? init generates it and prints it once; there is no fixed password. Change it on first login.

How does a public portal work? It is an anonymous catalogue at /pub/<slug>: the administrator chooses the apps, template and session time; per-IP limits apply and everything is audited.

Does the session survive if I close the browser? Yes. The process lives on the server; when you return, the tab reconnects to the same session with its PID.

Can it integrate with Active Directory? Yes: LDAP/AD is optional and coexists with local users. The user is mapped to their Linux account for the apps that need it.

Can I publish several sites on different Hosts? Yes. Sites stores Caddy-style site blocks in SQLite: exact or wildcard hosts, path routes to proxy apps or redirects, compression, headers and JSONL access logs. TLS terminates in front; sites are public, so WAF/rate-limit/blocklist/SSRF still apply but login/RBAC do not.

Can NSGateway replace Caddy/nginx? For Host/path routing of internal apps, yes. This version does not terminate TLS for sites (use nginx/Caddy/a load balancer in front), serve static files, do basic_auth or load-balance.

Where does the license go? At $NS_HOME/licenses/nsgateway.key; if NS_HOME is not set, at /opt/ns/licenses/nsgateway.key. The license identifier is nsgateway.

Which languages and themes are available? ES and EN; dark, light and high-contrast themes, with adjustable font size.

Also available in: es