HostsLab
A macOS desktop app for managing your /etc/hosts file and ~/.ssh/config. Built with Electron, React, and TypeScript.
HostsLab provides a visual interface to manage host entries and SSH connections without manually editing config files. Two tabs give you access to both tools from a single app.
Features
Hosts Tab
- View all entries from
/etc/hostsin a table - Add new host mappings
- Edit existing entries (IP and hostname)
- Toggle entries on/off (comments/uncomments the line)
- Delete entries
- System entries are protected from accidental modification
- Preserves comments, blank lines, and formatting in the hosts file
- Backs up the original hosts file before the first modification
- Elevated permissions via native macOS password prompt
SSH Config …
HostsLab
A macOS desktop app for managing your /etc/hosts file and ~/.ssh/config. Built with Electron, React, and TypeScript.
HostsLab provides a visual interface to manage host entries and SSH connections without manually editing config files. Two tabs give you access to both tools from a single app.
Features
Hosts Tab
- View all entries from
/etc/hostsin a table - Add new host mappings
- Edit existing entries (IP and hostname)
- Toggle entries on/off (comments/uncomments the line)
- Delete entries
- System entries are protected from accidental modification
- Preserves comments, blank lines, and formatting in the hosts file
- Backs up the original hosts file before the first modification
- Elevated permissions via native macOS password prompt
SSH Config Tab
- View all host entries from
~/.ssh/configin a table - Add, edit, and delete SSH connection entries
- Fields: Host (alias), HostName (IP/domain), User, Port, IdentityFile
- Dropdown shows detected SSH keys from
~/.ssh/ - Create new SSH keys (Ed25519, RSA 4096, ECDSA) directly from the app
- No sudo required — user owns
~/.ssh/config - Creates
~/.ssh/directory and config file if they don’t exist - Sets proper file permissions (700 for directory, 600 for config and private keys)
- Backs up original config on first edit
- Preserves comments, unknown directives, and wildcard Host blocks
How It Works
Architecture
The app follows Electron’s process model with a clear separation between main and renderer:
Renderer (React UI)
-- IPC bridge -->
Main Process (Node.js)
-- reads/writes -->
/etc/hosts (via sudo)
~/.ssh/config (direct)
~/.ssh/* (key scan + ssh-keygen)
-
Renderer process only sees typed objects (
HostEntry[],SSHEntry[]) — it never touches raw files -
Main process parses config files line-by-line, caching the full structure to preserve comments, blank lines, and formatting between saves
-
IPC channels:
-
hosts:read— returnsHostEntry[] -
hosts:save(entries)— writes to/etc/hostsvia elevatedcp, returns{success, error?} -
ssh:read— returnsSSHEntry[] -
ssh:save(entries)— writes to~/.ssh/configdirectly, returns{success, error?} -
ssh:listKeys— scans~/.ssh/for private keys, returnsSSHKey[] -
ssh:createKey(options)— runsssh-keygen, returns{success, keyPath?}
Hosts File Parsing
- Blank lines and
#comments are preserved as-is - Lines like
# 127.0.0.1 example.comare treated as disabled entries - Multi-hostname lines (e.g.
127.0.0.1 foo bar) are split into separate entries - System entries (
localhost,broadcasthost,::1 localhost) are marked read-only
SSH Config Parsing
- Parses
Hostblocks with indented key-value directives - Recognized directives: HostName, User, Port, IdentityFile
- Wildcard hosts (
Host *) are preserved in the file but not shown as editable entries - Unknown directives and comments are preserved on save
Saving
Hosts file:
- Serializes entries by walking the cached line structure
- Writes to a temp file
- Uses
osascriptwithdo shell script ... with administrator privilegesto copy the temp file to/etc/hostswith proper permissions - Re-reads the file to keep the cache in sync
- A backup of the original file is saved to the app’s user data directory on first save
SSH config:
- Serializes entries back into SSH config format (Host blocks with indented directives)
- Writes directly to
~/.ssh/configwith mode 600 - Re-reads the file to keep the cache in sync
- A backup is saved to the app’s user data directory on first save
SSH Key Detection
- Scans
~/.ssh/for private key files on app load - Detects known key types:
id_rsa,id_ed25519,id_ecdsa,*.pem - Also detects any file with an
OPENSSH PRIVATE KEYorPRIVATE KEYheader - Skips
.pubfiles,known_hosts,config, andauthorized_keys
SSH Key Creation
- Generates keys via
ssh-keygenwith no passphrase - Supports Ed25519 (recommended), RSA 4096, and ECDSA
- Sets permissions: 600 for private key, 644 for public key
- Refreshes the key list automatically after creation
Project Structure
src/
types.ts # Shared types (HostEntry, SSHEntry, SSHKey, ElectronAPI, etc.)
index.ts # Main process entry — creates window, registers IPC
preload.ts # Exposes electronAPI via contextBridge
renderer.ts # Renderer entry — loads CSS and app
app.tsx # React root mount
index.html # HTML shell
main/
hosts-file.ts # Parse, serialize, backup, save hosts file
ssh-config.ts # Parse, serialize, backup, save SSH config + key management
ipc-handlers.ts # ipcMain.handle for all IPC channels
components/
App.tsx # Top-level layout, tab navigation, state orchestration
HostsTable.tsx # Hosts entries table
HostRow.tsx # Single host row with toggle/edit/delete
EntryForm.tsx # Hosts add/edit modal form with validation
SSHTable.tsx # SSH entries table
SSHRow.tsx # Single SSH row with edit/delete
SSHEntryForm.tsx # SSH add/edit modal form with key dropdown
SSHKeyModal.tsx # Create new SSH key modal
Toast.tsx # Toast notifications
EmptyState.tsx # Empty state message
hooks/
useHosts.ts # Hosts CRUD state management + IPC calls
useSSH.ts # SSH CRUD state management + key operations + IPC calls
useToast.ts # Toast state management
styles/
app.css # All app styles
Development
Prerequisites
- Node.js (v18+)
- npm
- macOS (the elevated save uses
osascript)
Setup
npm install
Run
npm start
This launches the app in development mode with hot reload for the renderer process. Changes to main process files require a restart.
Build
npm run package
Produces a packaged .app in the out/ directory.
npm run make
Creates distributable installers (.dmg and .zip on macOS). Builds for both Intel (x64) and Apple Silicon (arm64).
Lint
npm run lint
Releases
Releases are built automatically via GitHub Actions. To create a new release:
git tag v1.0.0
git push origin v1.0.0
This triggers a workflow that:
- Builds the app on macOS for both Intel (x64) and Apple Silicon (arm64)
- Signs and notarizes the app with Apple via App Store Connect API key
- Produces
.dmgand.zipartifacts for each architecture - Creates a GitHub Release with auto-generated release notes and all downloadable artifacts
Download the latest release from the Releases page.
License
MIT