A modern Windows desktop application for managing SSH and serial port connections with an embedded terminal, built with WPF and .NET 9.
SshManager provides a graphical interface for storing and managing SSH host configurations and serial port connections, then connecting to them through a built-in terminal. It supports SSH connections to remote servers as well as serial port (COM) connections to embedded devices, network equipment, routers, and switches. Passwords are securely encrypted using Windows DPAPI, and the terminal supports full VT100/ANSI escape sequences including vim, tmux, docker, and htop.
- Windows 10/11 (64-bit)
- .NET 9.0 SDK or later
- WebView2 Runtime (usually pre-installed on Windows 10/11)
# Clone the repository
git clone <repository-url>
cd sshmanager
# Build the solution
dotnet build SshManager.sln
# Run the application
dotnet run --project src/SshManager.App/SshManager.App.csproj- The application should launch showing the main window with a split-view layout
- A sample host entry "Sample Host" is created on first run
- Double-click any host to open a terminal tab
- Host Management: Store SSH host configurations with hostname, port, username, and authentication settings
- Group Organization: Organize hosts into groups for better management
- Tag System: Apply colored tags to hosts for categorization and filtering
- Environment Variables: Configure per-host environment variables sent during SSH connection
- Embedded Terminal: Full-featured xterm.js terminal with WebView2 rendering
- Multiple Tabs: Open multiple terminal sessions in tabs
- Split Panes: Split the terminal view horizontally or vertically
- Quick Connect: Press
Ctrl+Kfor command palette-style host search and connection
- COM Port Support: Connect to serial devices (routers, switches, Arduino, Raspberry Pi, network equipment)
- Full Configuration: Configure baud rate (300-230400), data bits (5-8), stop bits, parity, and flow control
- Hardware Signal Control: Toggle DTR (Data Terminal Ready) and RTS (Request To Send) signals
- Send Break: Send break signal to connected devices
- Local Echo: Optional local character echo for half-duplex devices
- Line Endings: Configurable line endings (CRLF, LF, CR)
- Serial Quick Connect: Dialog to enumerate available COM ports and connect instantly
- Save Configurations: Store serial port settings alongside SSH hosts for repeated use
- Dual Driver Support: Uses System.IO.Ports (primary) with RJCP.SerialPortStream fallback for maximum compatibility
- SSH Agent: Use keys from your SSH agent or
~/.ssh/directory- Supports Pageant (PuTTY's SSH agent)
- Supports Windows OpenSSH Agent (Windows 10+)
- Automatic fallback to loading keys from
~/.ssh/directory
- Private Key File: Specify a path to a private key file
- Password: DPAPI-encrypted password storage (Windows user-specific)
- Kerberos/GSSAPI: Windows domain authentication with GSSAPI support
- Credential delegation for accessing additional resources
- Seamless integration with Active Directory environments
- 1Password: Fetch credentials from 1Password vaults at connection time via
op://secret references- Uses 1Password CLI with biometric unlock (Windows Hello)
- Supports both passwords and SSH keys
- Keyboard Interactive: Support for 2FA and other interactive prompts
- DPAPI Encryption: Passwords are encrypted using Windows Data Protection API
- Host Key Verification: Verify and store SSH host fingerprints
- Credential Caching: Optional secure in-memory credential caching with configurable timeout
- Session Lock Clearing: Automatically clear cached credentials when Windows session locks
- 1Password Integration: Fetch credentials at connection time via 1Password CLI with biometric authentication
- ProxyJump / Jump Hosts: Configure multi-hop SSH connections through bastion hosts
- Port Forwarding: Local, remote, and dynamic (SOCKS) port forwarding profiles
- Visual Tunnel Builder: Graph-based visual editor for complex tunnel configurations
- Drag-and-drop node placement for hosts and gateways
- Visual connection mapping between nodes
- Save and reuse tunnel profiles
- SFTP Browser: Graphical file browser for remote systems
- Dual-pane local/remote file view
- Drag-and-drop file transfers
- Folder upload and download with recursive directory handling
- Move files and create new folders
- Remote file editing with syntax highlighting
- File property viewer
- Remote File Editor: Edit remote files with syntax highlighting (AvalonEdit)
- Command Snippets: Save and reuse frequently used commands with categories
- Terminal Autocompletion: Intelligent command completion with multiple modes
- Session Recording: Record terminal sessions in ASCIINEMA v2 format for playback
- Session Playback: Replay recorded sessions with speed control (0.5x to 4x) and seeking
- Session Logging: Log terminal sessions to files
- Session Recovery: Restore disconnected sessions automatically
- Tracks session state for recovery on connection drops
- Session recovery dialog for manual restoration
- Broadcast Input: Send input to multiple terminals simultaneously
- Connection History: Track when and to which hosts you've connected
- Auto-Reconnect: Automatic reconnection with configurable retry policies
- Exponential backoff for retry attempts
- Per-host reconnection settings
- Connection Pooling: Reuse SSH connections for SFTP operations
- X11 Forwarding: Forward X11 display for graphical applications
- Terminal Statistics: Real-time bytes sent/received tracking
- Server Stats: View server resource information (uptime, disk usage)
- SSH Config Import: Import hosts from
~/.ssh/config - SSH Config Export: Export hosts to OpenSSH config format with ProxyJump support
- PuTTY Import: Import sessions from PuTTY registry
- Backup/Restore: Backup and restore all settings and hosts
- Cloud Sync: Sync hosts across devices via OneDrive (optional)
- Dark Theme: Modern Fluent Design with WPF-UI library
- System Tray: Minimize to system tray with quick-connect menu
- Terminal Themes: Customizable terminal color schemes
- Host Status: Monitor host availability with ping checks
sshmanager/
├── src/
│ ├── SshManager.Core/ # Domain models and shared types
│ │ ├── Models/ # HostEntry, HostGroup, AuthType, ConnectionType,
│ │ │ # SerialPortSettings, TunnelProfile, SavedSession, etc.
│ │ └── Exceptions/ # Custom exceptions (SshConnectionException, etc.)
│ │
│ ├── SshManager.Data/ # Data access layer (EF Core + SQLite)
│ │ ├── AppDbContext.cs # EF Core database context (17 DbSets)
│ │ ├── Repositories/ # Repository implementations
│ │ └── Services/ # Data services (cleanup, caching)
│ │
│ ├── SshManager.Security/ # Password encryption and key management
│ │ ├── DpapiSecretProtector.cs # DPAPI encryption
│ │ ├── SecureCredentialCache.cs # Secure memory credential caching
│ │ ├── SshKeyManagerService.cs # SSH key generation and management
│ │ ├── KeyEncryptionService.cs # Key passphrase management
│ │ ├── PpkConverter.cs # PPK ↔ OpenSSH key conversion
│ │ ├── OnePassword/ # 1Password CLI integration
│ │
│ ├── SshManager.Terminal/ # SSH, Serial, and terminal components
│ │ ├── Controls/ # WebTerminalControl, SshTerminalControl
│ │ ├── Models/ # SerialConnectionInfo, TerminalConnectionInfo
│ │ ├── Services/
│ │ │ ├── Connection/ # SSH connection services
│ │ │ ├── Display/ # Terminal display and theme services
│ │ │ ├── Lifecycle/ # Session lifecycle management
│ │ │ ├── Processing/ # Terminal output processing
│ │ │ ├── Recording/ # Session recording (ASCIINEMA format)
│ │ │ ├── Playback/ # Session playback with speed control
│ │ │ ├── Search/ # Terminal text search
│ │ │ ├── Stats/ # Terminal and server statistics
│ │ │ ├── SshConnectionService.cs # SSH connections
│ │ │ ├── SshTerminalBridge.cs # SSH ↔ terminal bridge
│ │ │ ├── SerialConnectionService.cs # Serial port connections
│ │ │ ├── SerialTerminalBridge.cs # Serial ↔ terminal bridge
│ │ │ ├── AgentKeyService.cs # SSH agent key management
│ │ │ ├── KerberosAuthService.cs # Kerberos/GSSAPI authentication
│ │ │ ├── AutoReconnectManager.cs # Auto-reconnection handling
│ │ │ ├── ConnectionPool.cs # Connection pooling
│ │ │ ├── TunnelBuilderService.cs # Visual tunnel builder logic
│ │ │ └── X11ForwardingService.cs # X11 display forwarding
│ │ └── Resources/ # terminal.html with xterm.js
│ │
│ └── SshManager.App/ # WPF UI application
│ ├── Views/
│ │ ├── Windows/ # MainWindow, SftpBrowserWindow, TextEditorWindow
│ │ ├── Dialogs/ # 35+ dialogs (HostEdit, Settings, TunnelBuilder, etc.)
│ │ └── Controls/ # TerminalPane, TunnelCanvas, CompletionPopup, etc.
│ ├── ViewModels/ # 60+ MVVM view models
│ ├── Services/ # Application services (Import/Export, Backup, Sync)
│ ├── Converters/ # 34+ WPF value converters
│ └── App.xaml.cs # DI container and app initialization
│
├── tests/
│ ├── SshManager.Terminal.Tests/ # Terminal unit and integration tests
│ └── SshManager.Security.Tests/ # Security and PPK conversion tests
│
├── docs/ # Documentation
└── SshManager.sln # Visual Studio solution file
SshManager supports two connection types defined in ConnectionType enum:
| Type | Description |
|---|---|
| Ssh | SSH connections to remote servers via SSH.NET |
| Serial | Serial port (COM) connections to local devices |
SshManager supports five authentication methods defined in AuthType enum:
| Type | Description |
|---|---|
| SshAgent | Uses SSH keys from your ~/.ssh/ directory or SSH agent (Pageant, Windows OpenSSH Agent) |
| PrivateKeyFile | Specify a custom private key file path with optional passphrase |
| Password | Store encrypted password in the database (DPAPI-encrypted) |
| Kerberos | Windows domain authentication using GSSAPI/Kerberos with optional credential delegation |
| OnePassword | Fetch passwords or SSH keys from 1Password vaults at connection time via op:// references |
SSH Agent Fallback Chain:
- Pageant (PuTTY's SSH agent) via Windows named pipes
- OpenSSH Agent (Windows 10+) via
\\.\pipe\openssh-ssh-agent - 1Password SSH Agent (replaces OpenSSH Agent on same pipe when enabled)
- Load keys from
~/.ssh/directory (id_rsa, id_ed25519, id_ecdsa, id_dsa) - Keyboard-interactive authentication as final fallback
Serial connections support comprehensive hardware configuration:
| Setting | Options | Default |
|---|---|---|
| Baud Rate | 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400 | 9600 |
| Data Bits | 5, 6, 7, 8 | 8 |
| Stop Bits | None, One, OnePointFive, Two | One |
| Parity | None, Odd, Even, Mark, Space | None |
| Handshake | None, XOnXOff, RequestToSend, RequestToSendXOnXOff | None |
| DTR Enable | true/false | true |
| RTS Enable | true/false | true |
| Local Echo | true/false | false |
| Line Ending | CRLF (\r\n), LF (\n), CR (\r) |
CRLF |
- Database: SQLite stored at
%LocalAppData%\SshManager\sshmanager.db - Logs: Rolling log files at
%LocalAppData%\SshManager\logs\ - Recordings: ASCIINEMA v2 files at
%LocalAppData%\SshManager\recordings\ - Terminal Themes: Custom themes stored in database
The terminal uses a bridge pattern to connect SSH.NET or serial ports with xterm.js:
SSH Connection:
SSH Server <--> SSH.NET ShellStream <--> SshTerminalBridge
|
v
User Input <--> xterm.js (WebView2) <--> WebTerminalBridge
Serial Connection:
Serial Device <--> System.IO.Ports <--> SerialTerminalBridge
|
v
User Input <--> xterm.js (WebView2) <--> WebTerminalBridge
Both connection types share the same terminal rendering layer (WebTerminalBridge + xterm.js), providing a consistent user experience.
- Click the + button or right-click in the host list
- Fill in the host details (hostname, port, username)
- Select authentication type and configure credentials
- Optionally assign to a group
- Click Save
- Double-click a host in the list, or
- Right-click and select Connect, or
- Select a host and press Enter, or
- Press Ctrl+K for Quick Connect, search for a host, and press Enter
- Click the Serial button in the toolbar (or use the menu)
- Select an available COM port from the dropdown (click Refresh to rescan)
- Configure connection settings:
- Baud Rate: Common values are 9600 or 115200
- Data Bits: Usually 8
- Stop Bits: Usually 1
- Parity: Usually None
- Flow Control: Usually None
- Optionally enable Local Echo for devices that don't echo input
- Click Connect for a temporary connection, or Connect & Save to save the configuration
While connected to a serial port:
- Use the DTR button to toggle Data Terminal Ready signal (useful for device reset)
- Use the RTS button to toggle Request To Send signal
- Use Send Break to send a break signal to the device (e.g., for entering ROMMON on Cisco devices)
- Right-click on a terminal tab
- Select Split Horizontal or Split Vertical
- Drag and drop sessions between panes
- Use keyboard shortcuts:
Ctrl+Shift+H(horizontal) orCtrl+Shift+V(vertical)
- Go to Settings (gear icon) or File > Import
- Select Import from SSH Config
- Browse to your
~/.ssh/configfile - Select hosts to import
- Click Import
- Go to Settings or File > Export
- Select Export to SSH Config
- Choose hosts to export (or select all)
- Configure export options (comments, groups, ProxyJump style)
- Click Export and choose destination file
- Connect to a host to open a terminal tab
- Click the Record button or use the keyboard shortcut
- Perform your terminal operations
- Click Stop Recording when finished
- Recording is saved in ASCIINEMA v2 format (.cast)
- Go to View > Recording Browser or click the recordings icon
- Select a recording from the list
- Use playback controls: play/pause, seek, adjust speed (0.5x to 4x)
- Recordings can be shared and played in external ASCIINEMA players
The Visual Tunnel Builder provides a graph-based interface for creating complex SSH tunnel configurations:
- Open View > Tunnel Builder or click the tunnel icon in the toolbar
- Add nodes by clicking "Add Node" and selecting:
- Source: Your local machine (starting point)
- Intermediate: Jump hosts/bastions (gateways)
- Destination: Target servers
- Connect nodes by clicking on a node and dragging to another
- Configure connections by clicking on edges to set port forwarding rules
- Save profile to reuse the tunnel configuration later
- Execute to establish all tunnels in the correct order
Tunnel Profile Example:
Local (Source) ──> Bastion (Intermediate) ──> Database (Destination)
└──> Web Server (Destination)
Forward graphical applications from remote servers:
- Edit a host and enable X11 Forwarding in Advanced Options
- Ensure an X server is running locally (e.g., VcXsrv, Xming)
- Connect to the host
- Run graphical applications (e.g.,
firefox,gedit,xclock) - The application window appears on your local display
Note: Requires X server installed and DISPLAY environment variable configured.
If a connection is unexpectedly dropped:
- The Session Recovery Dialog appears automatically when disconnected sessions are detected
- Select which sessions to restore
- Click Recover to re-establish connections and restore terminal state
- Sessions can be manually saved for later recovery via right-click menu
Send commands to multiple terminals simultaneously:
- Open multiple terminal tabs/panes to different hosts
- Enable Broadcast Mode via the toolbar or right-click menu
- Select which terminals should receive broadcast input
- Type in any terminal - input is sent to all selected terminals
- Disable broadcast mode when done
Use cases:
- Updating multiple servers simultaneously
- Running the same diagnostic command across a cluster
- Synchronized configuration changes
Access settings via the gear icon in the toolbar. Key settings include:
| Setting | Description |
|---|---|
| Terminal Theme | Select terminal color scheme |
| Terminal Font | Choose font family and size for terminal |
| Scrollback Buffer | Number of lines to keep in terminal history |
| Session Logging | Enable logging of terminal sessions |
| Session Recording | Automatically record terminal sessions |
| Credential Caching | Cache credentials in memory for repeated connections |
| Credential Cache Timeout | How long to keep cached credentials (minutes) |
| Auto Backup | Automatically backup database at intervals |
| Cloud Sync | Sync hosts via OneDrive |
| Keep-Alive Interval | Global SSH keep-alive interval (0-3600 seconds) |
| Auto-Reconnect | Attempt to reconnect on connection drop |
| Autocompletion Mode | Terminal autocompletion behavior (Off, Manual, Automatic) |
| 1Password | Use 1Password for credential storage (requires desktop app with CLI integration) |
The SQLite database is stored at:
%LocalAppData%\SshManager\sshmanager.db
To backup manually, copy this file when the application is closed.
# Debug build
dotnet build SshManager.sln
# Release build
dotnet build SshManager.sln -c Release
# Run tests
dotnet test# Self-contained Windows x64 executable
dotnet publish src/SshManager.App/SshManager.App.csproj -c Release -r win-x64 --self-contained- MVVM pattern with CommunityToolkit.Mvvm
- Dependency injection via Microsoft.Extensions.Hosting
- Async/await for all I/O operations
- Repository pattern for data access
Problem: Application fails to start with WebView2 error
Solution: Install the WebView2 Runtime from Microsoft: https://developer.microsoft.com/en-us/microsoft-edge/webview2/
Problem: SSH connections time out immediately
Solution:
- Verify the host is reachable:
ping hostname - Check firewall settings allow outbound port 22
- Verify SSH service is running on the target host
Problem: Saved password doesn't work
Solution:
- DPAPI-encrypted passwords are user-specific. If you've changed Windows users, re-enter the password
- Clear and re-enter the password in host settings
- Check if the remote server requires a different authentication method
Problem: Terminal shows garbled text or wrong colors
Solution:
- Try a different terminal theme in Settings
- Clear the terminal (right-click > Clear)
- Check the remote system's
$TERMenvironment variable
Problem: COM port doesn't appear in the dropdown
Solution:
- Click Refresh to rescan for available ports
- Check Device Manager to verify the port is recognized by Windows
- Ensure the USB-to-serial adapter drivers are installed
- Try unplugging and reconnecting the cable
Problem: Cannot connect to serial port
Solution:
- Verify the port isn't already in use by another application (PuTTY, Arduino IDE, etc.)
- Check the baud rate matches the device configuration (common: 9600, 115200)
- Try different data bits/parity/stop bits settings
- Some devices require DTR or RTS enabled to communicate
Problem: Connected but not receiving any data
Solution:
- Enable Local Echo to see what you're typing
- Try pressing Enter to prompt the device
- Check the line ending setting (some devices expect LF only, others CRLF)
- Toggle DTR/RTS signals - some devices need these to enable transmission
- Verify the cable is a data cable, not charge-only (for USB devices)
Problem: Receiving data but it's unreadable
Solution:
- Verify the baud rate matches the device exactly
- Check data bits (8 is most common) and parity settings
- Ensure flow control settings match the device
- Try a lower baud rate for long cable runs
- ARCHITECTURE.md - Detailed system architecture
- GETTING_STARTED.md - Step-by-step beginner guide
- API.md - Terminal services API reference for developers
- CLAUDE.md - Developer reference for AI assistants
| Component | Technology |
|---|---|
| Framework | .NET 9, WPF |
| UI Library | WPF-UI (Fluent Design) |
| MVVM | CommunityToolkit.Mvvm |
| Database | SQLite via EF Core |
| SSH | SSH.NET |
| Serial | System.IO.Ports + RJCP.SerialPortStream |
| Terminal | xterm.js via WebView2 |
| Logging | Serilog |
| Credentials | Windows DPAPI + 1Password CLI |
[License information to be added]