Managing SSH access across a growing infrastructure can become complicated surprisingly quickly.
At first, it might be as simple as:
Admin laptop
│
└── SSH ──> Linux server
But as an infrastructure environment grows, the architecture often starts looking more like this:
┌── Web Server
├── Database
Admin ── VPN ──> Network ├── Kubernetes Node
├── Monitoring
├── Jenkins
└── Internal Services
Now add multiple engineers, contractors, administrators, different environments, SSH keys, jump hosts, VPN accounts, firewall rules, and the requirement to audit who accessed what.
The problem becomes less about “How do I SSH into a server?” and more about:
“How do I securely control and audit infrastructure access at scale?”
This is the problem I wanted to explore with GateTerm.
What is GateTerm?
GateTerm is a lightweight, self-hostable web-based bastion / jump server.
Instead of giving users direct SSH access to infrastructure, users authenticate to a single HTTPS endpoint.
From that web interface they can:
- Browse authorized servers
- Open SSH terminals
- Run commands
- Create SSH port forwards
- Access internal web applications
- Use RBAC-controlled infrastructure access
- Have their sessions audited
- Replay previous terminal sessions
The basic concept is:
Internet / Corporate Network
│
│ HTTPS
▼
┌─────────────────┐
│ nginx / TLS │
│ Reverse Proxy │
└────────┬────────┘
│
▼
┌─────────────────┐
│ GateTerm │
│ Bastion │
│ │
│ SSO / RBAC │
│ SSH / Tunnels │
│ Audit │
└────────┬────────┘
│
Outbound SSH
│
┌───────────────┼───────────────┐
▼ ▼ ▼
Server A Server B Server C
The important architectural decision is that GateTerm itself becomes the SSH stepping point.
Remote servers do not need a GateTerm agent.
The bastion establishes outbound SSH connections to the infrastructure.
Why Build Another Bastion?
There are already many solutions for infrastructure access.
VPNs, traditional bastion hosts, SSH jump hosts, identity-aware proxies, zero-trust platforms, and commercial privileged-access-management products can all solve parts of this problem.
The goal with GateTerm isn’t to replace every one of them.
Instead, the idea is to keep the architecture deliberately simple.
A traditional bastion might look like:
Engineer
│
│ SSH
▼
Bastion
│
├── SSH ──> Server A
├── SSH ──> Server B
└── SSH ──> Server C
GateTerm keeps this fundamental model.
The difference is that the user interacts with the bastion through a browser:
Browser
│
│ HTTPS
▼
GateTerm
│
├── SSH ──> Server A
├── SSH ──> Server B
└── SSH ──> Server C
This avoids introducing agents, reverse tunnels, or complicated multiplexing mechanisms into every server.
The result is a relatively small architecture with a single infrastructure access point.
The Security Model
One of the most important design principles behind GateTerm is:
Users should not need SSH private keys distributed across the infrastructure.
Instead, the bastion owns the credentials required to reach the servers.
The user authenticates to GateTerm.
GateTerm determines whether the user is allowed to access the requested server.
Then GateTerm establishes the SSH connection.
Conceptually:
User
│
│ SSO
▼
GateTerm
│
│ "Is this user allowed?"
▼
RBAC / Policy
│
│ YES
▼
GateTerm SSH credentials
│
│ SSH
▼
Remote Server
This creates a separation between:
Authentication
Who are you?
and
Authorization
What infrastructure are you allowed to access?
and
Infrastructure credentials
What credentials are actually used to access the server?
That separation becomes particularly useful in larger environments.
SSO First
GateTerm is designed around a single web entry point.
Users authenticate before they can access infrastructure.
The project supports identity providers through OIDC, including systems such as:
- Google Workspace
- Keycloak
- Auth0
- Microsoft Entra ID
It also supports OAuth2 providers such as GitHub and GitLab.
The desired user experience becomes:
https://gateterm.example.com
│
▼
SSO Login
│
▼
GateTerm Dashboard
│
┌──────┴──────┐
▼ ▼
Servers Policies
│
▼
SSH Terminal
There is no need for the user to manually configure VPN routes or manage SSH keys for every environment.
RBAC: Don’t Give Everyone Everything
Authentication alone isn’t enough.
An infrastructure gateway also needs authorization.
GateTerm uses RBAC and policies to control access to infrastructure.
For example:
Developer
├── dev-server-01
├── dev-server-02
└── staging-server-01
Operations
├── dev-*
├── staging-*
└── production-*
Database Team
├── db-prod-01
└── db-prod-02
The important part is that authorization is not only checked when the user logs into the application.
Access is also checked when the user attempts to establish a connection.
This provides another enforcement point:
User Login
│
▼
Authentication
│
▼
RBAC
│
▼
Server Selection
│
▼
Authorization Check
│
▼
SSH Connection
This prevents the web interface from becoming merely a visual wrapper around unrestricted SSH access.
A Web-Based SSH Terminal
One of the most visible parts of GateTerm is the browser terminal.
The frontend uses Svelte and xterm.js to provide an interactive terminal directly in the browser.
Instead of:
ssh user@server.example.com
the workflow becomes:
GateTerm
│
├── Server A
│ └── Terminal
│
├── Server B
│ └── Terminal
│
└── Server C
└── Terminal
Multiple sessions can remain open simultaneously.
This is useful for operations work where an engineer may need to monitor several machines at once.
For example:
┌────────────────┬────────────────┬────────────────┐
│ prod-web-01 │ prod-web-02 │ prod-db-01 │
│ │ │ │
│ $ top │ $ journalctl │ $ mysql │
│ $ systemctl │ $ tail -f │ │
│ │ │ │
└────────────────┴────────────────┴────────────────┘
Port Forwarding Without a VPN
This is probably one of the more interesting parts of the project.
SSH isn’t only useful for terminals.
It is also an extremely useful networking tool.
For example, suppose a MySQL server is only reachable from the internal network:
Internet
X
│
│
▼
MySQL Server
10.10.20.50:3306
Normally, you might connect through a VPN or manually create an SSH tunnel:
ssh -L 3306:10.10.20.50:3306 user@bastion
GateTerm provides a controlled mechanism for doing essentially the same thing through the bastion.
For example:
gateterm tunnel \
--node <node_id> \
--host db.internal \
--port 3306 \
--user <ssh-login> \
--local 127.0.0.1:3306
You can then use the local port:
mysql \
-h 127.0.0.1 \
-P 3306 \
-u app \
-p
This can be useful for:
- MySQL
- PostgreSQL
- Redis
- SSH
- Internal APIs
- Other TCP services
The important difference is that port forwarding is itself subject to authorization policies and the AllowPortForwarding permission.
Access Internal Web Applications From a Browser
GateTerm also supports HTTP web-console forwarding.
Imagine you have an internal application:
http://10.10.20.100:8080
and that server isn’t directly reachable from your workstation.
Instead of creating a VPN connection, GateTerm can proxy the HTTP application through the bastion using the SSH connection.
Conceptually:
Browser
│
│ HTTPS
▼
GateTerm
│
│ SSH tunnel
▼
Internal Application
10.10.20.100:8080
This is particularly useful for internal dashboards and administrative interfaces.
For example:
- Kibana
- Grafana
- Jenkins
- Internal admin applications
- Monitoring dashboards
- Development interfaces
GateTerm’s web console is designed specifically for HTTP/HTTPS services, while raw TCP services use the CLI tunnel mechanism.
Session Auditing
Infrastructure access without auditing can become problematic.
Imagine an administrator says:
“The production configuration changed, but I don’t know who did it.”
With traditional SSH access, answering that question may require correlating:
- Linux logs
- SSH logs
- shell history
- sudo logs
- SIEM events
- individual user accounts
GateTerm takes a different approach by recording session information.
A session can contain:
User
Server
SSH principal
Start time
End time
Commands
PTY output
Sessions can then be searched by user, host, or time range.
Administrators or auditors can also replay terminal sessions through the web interface.
This changes the operational model from:
"Someone logged into the server."
to:
"John accessed production-db-01
at 10:32,
using principal postgres-admin,
and executed these commands."
That distinction can be extremely valuable for production environments.
OpenBao Integration
Another interesting direction is integration with OpenBao.
Instead of permanently storing SSH credentials, the architecture can eventually use short-lived SSH certificates.
The conceptual model becomes:
User
│
▼
GateTerm
│
│ request temporary credential
▼
OpenBao
│
│ short-lived SSH certificate
▼
GateTerm
│
│ SSH
▼
Server
This follows the principle of reducing long-lived credentials.
Rather than:
Permanent SSH private key
↓
Always valid
the goal becomes:
Short-lived certificate
↓
Limited lifetime
↓
SSH access
↓
Expires
OpenBao integration is an enhancement to the core architecture rather than a requirement for GateTerm to function.
Docker Deployment
GateTerm is designed to be relatively easy to deploy.
The repository provides Docker Compose deployment with GateTerm and nginx.
The architecture looks like:
HTTPS :443
│
▼
┌───────────────┐
│ nginx │
│ TLS / Proxy │
└───────┬───────┘
│
▼
┌───────────────┐
│ GateTerm │
│ Container │
└───────┬───────┘
│
outbound SSH
│
┌─────────────┼─────────────┐
▼ ▼ ▼
Linux 1 Linux 2 Linux 3
Only nginx is exposed publicly.
The GateTerm container itself isn’t published directly to the host.
The container is also designed with several hardening settings, including:
no-new-privileges
read-only root filesystem
capability dropping
non-root execution
The repository uses a persistent volume for the GateTerm data, including the CA signing material and SQLite database.
Why the Architecture Is Interesting
There are many ways to build infrastructure access platforms.
A common temptation is to introduce more components:
VPN
+
Agents
+
Reverse tunnels
+
Message broker
+
Proxy
+
Identity service
+
Credential service
+
Gateway
GateTerm takes almost the opposite approach.
It tries to keep the architecture centered around one strong component:
GateTerm
│
┌────────┼────────┐
│ │ │
SSH Tunnel Audit
│ │ │
└────────┼────────┘
│
Servers
The remote machines don’t need an application agent.
They only need to trust the SSH credentials or CA used by the bastion.
This keeps the infrastructure side relatively simple.
The Security Boundary
The most important thing to understand about GateTerm is that the bastion becomes a highly privileged security boundary.
That is both its biggest strength and its biggest responsibility.
If GateTerm can reach:
Production
Development
Staging
Databases
Kubernetes
Internal applications
then compromising GateTerm could potentially provide access to all of them.
Therefore, the bastion should not be treated like an ordinary application server.
A recommended architecture is:
Internet
│
▼
┌──────────────┐
│ Firewall/WAF │
└──────┬───────┘
HTTPS
│
▼
┌──────────────┐
│ nginx │
└──────┬───────┘
│
▼
┌──────────────┐
│ GateTerm │
│ Bastion │
└──────┬───────┘
│
SSH egress only
│
┌─────────────┼─────────────┐
▼ ▼ ▼
Server A Server B Server C
And the firewall should enforce something like:
Server A
SSH <- GateTerm only
Server B
SSH <- GateTerm only
Server C
SSH <- GateTerm only
This creates a very clear network security boundary.
GateTerm vs Traditional VPN
It is important to clarify that GateTerm doesn’t necessarily make VPNs obsolete.
They solve different problems.
| VPN | GateTerm |
|---|---|
| Provides network-level access | Provides application/infrastructure access |
| User joins a network | User accesses authorized resources |
| Often broad network visibility | RBAC-controlled resource visibility |
| Client configuration required | Browser-first experience |
| Doesn’t inherently provide terminal auditing | Session auditing |
| Can expose many internal services | Access can be restricted by policy |
| Useful for general private networking | Useful for controlled infrastructure access |
A VPN essentially says:
“You are now on the network.”
GateTerm aims for:
“You are authenticated, and you may access these specific infrastructure resources.”
That is a fundamentally different security model.
Where GateTerm Fits
I see GateTerm fitting particularly well in environments such as:
Small DevOps teams
A small infrastructure team can provide a single access portal instead of maintaining VPN access and SSH configuration for every engineer.
MSP environments
For teams managing multiple customer environments, centralized access and auditing can become extremely valuable.
Internal enterprise infrastructure
GateTerm can act as a controlled access layer between employees and sensitive infrastructure.
Production environments
RBAC and session auditing can provide additional controls around production access.
Lab environments
It can also be useful simply because accessing servers through a browser is convenient.
The Bigger Idea
The interesting part of GateTerm isn’t really the web terminal.
Web terminals already exist.
The interesting part is combining several infrastructure-access concepts into one relatively small architecture:
┌────────────────────┐
│ GateTerm │
├────────────────────┤
│ │
│ SSO │
│ RBAC │
│ SSH │
│ Web Terminal │
│ Port Forwarding │
│ Web Console │
│ Session Audit │
│ SSH Certificates │
│ │
└─────────┬──────────┘
│
▼
Infrastructure
Instead of asking every user to understand the network topology, SSH keys, VPN routes, jump hosts, and internal IP addresses, the organization can provide one controlled entry point.
That is the real value of a bastion.
Final Thoughts
GateTerm started from a fairly simple infrastructure problem:
How can we give people convenient access to servers without giving everyone direct network access and SSH credentials?
The resulting architecture is intentionally straightforward:
User
│
│ HTTPS
▼
GateTerm
│
┌──────┼──────┐
│ │ │
SSH Tunnel Audit
│ │ │
└──────┼──────┘
│
▼
Internal Servers
The project combines a familiar technology—SSH—with modern access-control concepts such as SSO, RBAC, short-lived credentials, centralized auditing, and browser-based access.
Most importantly, it doesn’t require installing an agent on every server.
For infrastructure teams that want a lightweight, self-hosted alternative to a traditional VPN-based access model, this makes GateTerm an interesting project to experiment with.
The project is open source and available on GitHub:
If you’re managing Linux infrastructure, the architecture is worth exploring—not necessarily because every environment needs another bastion, but because it raises an important question:
Can infrastructure access be made as simple as opening a browser while still retaining the security and auditability expected from production systems?
GateTerm is an experiment toward that direction.