Skip to main content

Modern SSH terminal widget for PyQt6 with credential vault and jump host support

Project description

nterm

A modern SSH terminal for network engineers

PyQt6 terminal widget with encrypted credential vault, jump host chaining, YubiKey/FIDO2 support, and legacy device compatibility.

Built for managing hundreds of devices through bastion hosts with hardware security keys.

nterm screenshot


Features

Terminal

  • xterm.js rendering via QWebEngineView — full VT100/ANSI support
  • Built-in themes: Catppuccin, Dracula, Nord, Solarized, Gruvbox (dark/light/hybrid)
  • Custom YAML themes with independent terminal and UI colors
  • Tab or window per session — pop sessions to separate windows
  • Unicode, emoji, box-drawing characters

Authentication

  • SSH Agent with YubiKey/FIDO2 hardware keys
  • Password, key file, keyboard-interactive, certificate auth
  • Multiple auth methods with automatic fallback
  • RSA SHA-1 fallback for legacy devices (OpenSSH < 7.2)
  • Legacy crypto support for old Juniper/Cisco gear

Connection Management

  • Jump host chaining (unlimited hops)
  • Auto-reconnection with exponential backoff
  • Connection profiles in YAML/JSON
  • Pattern-based credential resolution

Credential Vault

  • AES-256 encryption with PBKDF2 (480,000 iterations)
  • Pattern matching — map credentials to hosts by wildcard or tag
  • Cross-platform keychain: macOS Keychain, Windows Credential Locker, Linux Secret Service
  • Full PyQt6 management UI

Screenshots

Gruvbox Hybrid Theme Credential Manager
gruvbox vault
Connection Dialog Multi-vendor Support
connect neofetch

Installation

From PyPI

pip install nterm

# Optional: system keychain support
pip install nterm[keyring]

# Run
nterm

From Source

git clone https://github.com/scottpeterman/nterm.git
cd nterm

# Create virtual environment
python -m venv .venv
source .venv/bin/activate  # Linux/macOS
# .venv\Scripts\activate   # Windows

# Install in development mode
pip install -e .

# Optional: system keychain support
pip install keyring

# Run
nterm
# or
python -m nterm

Requirements

  • Python 3.10+
  • PyQt6 with WebEngine
  • paramiko
  • cryptography
  • pyyaml

Platform Support

Platform PTY Keychain
Linux ✅ Native Secret Service
macOS ✅ Native macOS Keychain
Windows 10+ ✅ pywinpty Credential Locker

Quick Start

As a Widget

from PyQt6.QtWidgets import QApplication, QMainWindow
from nterm import ConnectionProfile, AuthConfig, SSHSession, TerminalWidget, Theme

app = QApplication([])

terminal = TerminalWidget()
terminal.set_theme(Theme.gruvbox_hybrid())

profile = ConnectionProfile(
    name="router",
    hostname="192.168.1.1",
    auth_methods=[AuthConfig.password_auth("admin", "secret")],
)

session = SSHSession(profile)
terminal.attach_session(session)
session.connect()

window = QMainWindow()
window.setCentralWidget(terminal)
window.resize(1000, 700)
window.show()

app.exec()

With Credential Vault

from nterm.vault import CredentialStore, CredentialResolver

store = CredentialStore()
store.unlock("master-password")

# Add credential with pattern matching
store.add_credential(
    name="network-devices",
    username="admin",
    password="secret",
    match_hosts=["*.network.corp", "192.168.1.*"],
    match_tags=["cisco", "juniper"],
)

# Auto-resolve credentials by hostname
resolver = CredentialResolver(store)
profile = resolver.resolve_for_device("switch01.network.corp", tags=["cisco"])

session = SSHSession(profile)
session.connect()

Themes

Built-in

Theme.default()         # Catppuccin Mocha
Theme.dracula()         # Dracula
Theme.nord()            # Nord
Theme.solarized_dark()  # Solarized Dark
Theme.gruvbox_dark()    # Gruvbox Dark
Theme.gruvbox_light()   # Gruvbox Light
Theme.gruvbox_hybrid()  # Dark UI + Light terminal

Custom YAML

# ~/.nterm/themes/my-theme.yaml
name: my-theme

terminal_colors:
  background: "#1a1b26"
  foreground: "#c0caf5"
  cursor: "#c0caf5"
  black: "#15161e"
  red: "#f7768e"
  green: "#9ece6a"
  yellow: "#e0af68"
  blue: "#7aa2f7"
  magenta: "#bb9af7"
  cyan: "#7dcfff"
  white: "#a9b1d6"
  # ... bright variants

# UI chrome (can differ from terminal)
background_color: "#1a1b26"
foreground_color: "#c0caf5"
border_color: "#33467c"
accent_color: "#7aa2f7"

Jump Hosts

profile = ConnectionProfile(
    name="internal-db",
    hostname="db01.internal.corp",
    auth_methods=[AuthConfig.agent_auth("dbadmin")],
    jump_hosts=[
        JumpHostConfig(
            hostname="bastion.corp.com",
            auth=AuthConfig.agent_auth("youruser"),
            requires_touch=True,
            touch_prompt="Touch YubiKey for bastion...",
        ),
    ],
)

Legacy Device Support

nterm automatically handles old network equipment:

  • RSA SHA-1 fallback for OpenSSH < 7.2 servers
  • Legacy KEX algorithms: diffie-hellman-group14-sha1, group1-sha1
  • Legacy ciphers: aes128-cbc, 3des-cbc
  • Auto-detection: tries modern crypto first, falls back as needed

Tested with:

  • Junos 14.x (2016)
  • Cisco IOS 12.2
  • Old Arista EOS
  • Any device running OpenSSH 6.x

Architecture

nterm/
├── connection/        # ConnectionProfile, AuthConfig, JumpHostConfig
├── session/
│   ├── ssh.py         # SSHSession (Paramiko) with legacy fallback
│   ├── interactive_ssh.py   # Native SSH + PTY
│   └── pty_transport.py     # Cross-platform PTY
├── terminal/
│   ├── widget.py      # TerminalWidget (PyQt6 + xterm.js)
│   └── bridge.py      # Qt ↔ JavaScript bridge
├── theme/
│   ├── engine.py      # Theme system
│   └── themes/        # YAML theme files
├── vault/
│   ├── store.py       # Encrypted credential storage
│   ├── resolver.py    # Pattern-based resolution
│   └── manager_ui.py  # PyQt6 credential manager
└── manager/           # Session tree, connection dialogs

Related Projects


License

GPLv3


Contributing

Contributions welcome:

  • Additional themes
  • Windows testing
  • Session recording/playback
  • Telnet/serial support

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ntermqt-0.1.1.tar.gz (158.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ntermqt-0.1.1-py3-none-any.whl (176.4 kB view details)

Uploaded Python 3

File details

Details for the file ntermqt-0.1.1.tar.gz.

File metadata

  • Download URL: ntermqt-0.1.1.tar.gz
  • Upload date:
  • Size: 158.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for ntermqt-0.1.1.tar.gz
Algorithm Hash digest
SHA256 0ef9c4131cd552603f01e08e3319c085ab741558f8576930cc39390cf25ce411
MD5 968bfc446c7c7f45c010375779eeb118
BLAKE2b-256 3ba6c85ba19ed8c0291d186ca6c87f430dbe7cc4cc2916debdaa0a2dadd18f37

See more details on using hashes here.

File details

Details for the file ntermqt-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: ntermqt-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 176.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for ntermqt-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0765383046f608b01bee5471acd9b9c127fcf72fd3499195b32b1962a8b39faf
MD5 b9a183958b254607902957e1e37b9ea4
BLAKE2b-256 9086c32656565d5ab96448beb59a872ca9b70add94abaad024de262e5ffc7e5a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page