| Host | Domain | Keys | Wildcard | Copy |
|---|---|---|---|---|
| {{ r.host }} | {{ r.domain || '—' }} | {{ r.keyCount }} | {{ r.wild ? 'Yes' : 'No' }} | |
| No rows | ||||
| Host | Issue | Copy |
|---|---|---|
| {{ w.host }} | {{ w.issue }} | |
| No issues found. | ||
| Severity | Host | Issue | Recommendation | Copy |
|---|---|---|---|---|
| {{ finding.severityLabel }} | {{ finding.host || 'Global' }} | {{ finding.issue }} | {{ finding.recommendation }} |
| Directive | Hosts | Unique values | Missing | Example value | Copy |
|---|---|---|---|---|---|
| {{ row.key }} | {{ row.hostCount }} | {{ row.uniqueValues }} | {{ row.missingHosts }} | {{ row.sampleValue || '—' }} |
~/.ssh/config. Download and replace it manually when done.
SSH client configuration is the layer that turns a short alias into a real connection plan. A single Host block can decide which server name to reach, which account to use, which key to offer, whether a jump host is involved, and whether local or remote ports should be forwarded. When that file grows over time, the hardest part is often not typing the directives. It is seeing which host blocks are clear, which ones drifted, and which settings quietly widen trust.
This editor is built for that review pass. You can drop or paste a config, split it into editable host blocks, search across patterns and values, group entries by wildcard usage or domain suffix, reorder them, and rebuild a cleaner version for copy or download. The same session also exposes a JSON view, a structural lint table, a security review table, a directive insights table, and a diff against the imported baseline.
That combination is useful because SSH mistakes are often subtle rather than dramatic. A broad wildcard such as db-*, a permissive StrictHostKeyChecking setting, agent forwarding, or a forwarded port bound to 0.0.0.0 can sit in a config for months before anyone stops to review it. A long file can still be valid enough to work while being hard to audit safely.
Everything the editor does stays in the browser session. Parsing, matching, preview generation, diffing, JSON export, CSV export, and DOCX export all happen locally in the page. You still replace your real ~/.ssh/config yourself, and the editor does not verify remote host keys, test whether files exist on disk, or log into any server.
The most important limit is that this is a config review surface, not a full OpenSSH evaluator. It does not expand included files, does not execute Match conditions, does not merge global defaults from Host * into later stanzas, and does not preserve comments and non-host lines in their exact original positions. If your workflow depends heavily on inheritance, conditional logic, or layered includes, treat the rebuilt file as a draft that still needs a deliberate SSH-aware check.
The editor reads the imported text as a series of visible Host stanzas. Inside each stanza it stores directive rows, accepts both known SSH client keys and custom keys, and rebuilds the output from that structured view. Leading comments plus non-host lines such as Include and Match can be retained as top-level text when you enable preservation, but the editor does not execute them and does not keep them anchored to their original locations inside the file.
Host blocks into editable rows
optionally preserve top-level comments, Include, and Match lines as shared non-host text
apply optional sorting, key normalization, de-duplication, and header comment
generate preview, JSON, lint, security findings, directive insights, and diff output
The cleanup controls are deterministic, which makes them predictable but also means they can change meaning if you use them carelessly. OpenSSH normally uses the first obtained value for most parameters, while this editor's optional de-duplication keeps the last repeated key inside a host block. That is an editing choice, not an attempt to reproduce final SSH resolution. It matters most when repeated directives are intentional.
| Option | What it changes | Why to review it carefully |
|---|---|---|
| Sort hosts alphabetically | Reorders host stanzas by host pattern in the rebuilt file. | Safe for readability, but it can hide the original authoring order you may want when comparing changes. |
| Sort keys within each host | Applies the editor's fixed directive order before rendering each host block. | Good for cleanup, but it rearranges the file and makes the diff broader. |
| Normalize key case | Converts known directive names to canonical SSH-style casing such as HostName and StrictHostKeyChecking. |
Useful for consistency, but cosmetic changes can make a quick diff look larger than the functional change really is. |
| De-duplicate repeated keys | Keeps the last repeated directive name inside the same host block. | Potentially risky because repeated keys can be intentional for directives such as IdentityFile, LocalForward, or RemoteForward. |
| Preserve non-Host lines | Prepends stored non-host lines before the rebuilt host blocks. | Retention is useful, but the original placement and conditional context are not preserved. |
| Include header comment | Adds a generated comment line at the top of the output. | Helpful for handoff, but it changes the file even if no host logic changed. |
The Match tester is intentionally lightweight. It compares the sample hostname against whitespace-separated Host patterns, supports * and ?, and matches without regard to letter case. It is useful for quick sanity checks on aliases and wildcards, but it is not a full simulation of OpenSSH pattern logic. Negated patterns, inherited defaults, and conditional Match criteria are outside its model.
Grouping is also a convenience view rather than SSH resolution. Wildcard grouping simply separates patterns that contain * or ?. Domain grouping pulls the suffix from the first visible host token after its first dot. That makes it easy to scan a fleet, but it is not DNS-aware and does not reflect hostname canonicalization.
| Surface | What it checks | What it does not prove |
|---|---|---|
| Lint | Empty host patterns, hosts with no directives, repeated keys, and empty directive values. | A repeated key warning does not automatically mean the SSH config is invalid, because some directives may intentionally appear more than once. |
| Security | Root login, missing or relaxed host-key checks, missing IdentityFile, password authentication, agent forwarding, wide local or remote binds, ControlMaster without ControlPersist, missing HostName, and UpdateHostKeys no. |
A quiet table does not guarantee the effective SSH session is safe when your real config depends on inherited defaults, includes, or conditional logic. |
| Insights | How many hosts use each directive, how many distinct values appear, how many hosts are missing it, and one sample value. | It shows coverage and drift, not whether a directive is appropriate for every host. |
| Diff | Line-by-line changes between the imported baseline and the rebuilt output. | It confirms what changed in text form, not what OpenSSH would ultimately apply after all matching rules are processed. |
For smaller files the diff view uses a more contextual comparison, while very large comparisons fall back to a simpler line-by-line pass so the page stays responsive. The JSON export collects the visible host blocks, line details, wildcard flags, non-host text, and current cleanup options. The Hosts, Security, and Insights tabs also support CSV or DOCX export so you can hand a review summary to someone who does not need the raw config itself.
The best way to use the editor is as a controlled rewrite of text you already have. Import the real config first, even if you expect to clean most of it up, because that gives the diff view a true baseline and lets the summary box reflect the file you actually maintain.
Once the file is loaded, decide whether you are dealing with independent host stanzas or with layered SSH logic. If each host block is fairly self-contained, the editor can be a strong cleanup aid. If the file relies on Host * defaults, nested includes, or conditional Match rules, the editor is still useful for inspection, but the result needs more manual judgment because the final runtime config may inherit behavior that the page never models.
Search and grouping are the safest first moves. They help you spot families of hosts before you change anything. A wildcard-heavy file often benefits from grouping by wildcard first, because broad patterns deserve more scrutiny than literal one-off aliases. Domain grouping is helpful when you maintain separate environments such as production, staging, and internal service networks.
Use cleanup switches one at a time. Sorting and key normalization are usually low-risk readability changes. De-duplication deserves a slower review because repeated lines are not always mistakes in SSH. Multiple IdentityFile entries can be intentional, and multiple forwarding rules are a normal part of some workflows. In this editor, repeated keys are treated as something to review structurally, not as a promise that OpenSSH would reject them.
The security view is strongest when it helps you rank what to read next. A high-severity row means a setting deserves an explicit decision. It does not mean every use is impossible. The same is true in reverse. No findings means the visible rows did not trigger the editor's built-in rules. It does not mean the remote host is trusted, that included files are clean, or that inherited defaults are harmless.
Finish every serious edit in the preview and the diff. The preview shows the exact text you are about to copy or download. The diff shows whether the rebuilt file changed only where you intended. If those two views still look larger or stranger than expected, stop there and review before replacing your real SSH config.
Lint, Security, and Insights tabs together. Structural warnings tell you where the text is messy. Security findings tell you where trust deserves a closer look. Insights show where values drift across hosts.Diff tab, then use copy or download to export the result. Replace your actual SSH config manually when you are satisfied, because the editor does not write to ~/.ssh/config directly.The summary box is a fast triage layer, not a full audit. Host count tells you how many visible Host stanzas were parsed. Wildcard count tells you how much pattern-based matching is in play. Warning and alert badges tell you where to start reading next. The Known keys badge is the size of the editor's built-in directive catalog, not a count of how many directive types your imported file uses.
The Hosts tab is the best quick inventory view. It shows each host pattern, a rough domain label, the number of directives that survive the current output options, and whether the pattern contains wildcards. The copy action on that table is useful when you want to share one host block for review without sharing the entire config.
The JSON tab is a structured snapshot of what the page currently sees. It is useful when you want to archive the review state, inspect host rows programmatically, or compare how option toggles change the reconstructed model. Because it mirrors the editor's internal view, it also reflects the editor's limits. It is not the same thing as OpenSSH's fully evaluated runtime result.
Lint is best read as structural review. Clear empty keys and empty values early, then judge duplicate-key warnings with SSH semantics in mind.Security is best read as review priority. A finding means the visible setting deserves intent and context, not blind removal.Insights is best read as a drift map. High unique-value counts or many missing hosts often show where configuration sprawl has crept in.Diff is the final check before export. If the diff is broader than expected, your cleanup options probably changed more than you intended.A compact deployment alias. Say your file contains Host web-prod, HostName web01.internal, User deploy, IdentityFile ~/.ssh/id_ed25519, and StrictHostKeyChecking yes. The editor will show one host, no wildcard, and usually no security findings. In that case the page is acting as a clean confirmation that the visible alias is explicit and easy to copy into a new workstation or teammate setup.
A wildcard that needs a deliberate trust decision. Now picture Host db-* with User root, StrictHostKeyChecking accept-new, ForwardAgent yes, and LocalForward 0.0.0.0:5432 db.internal:5432. The editor will surface that block quickly because the wildcard count goes up and the security table reports several concerns. The point is not that the block can never be justified. The point is that one permissive profile now applies broadly, so the file deserves review before that pattern spreads further.
A config that relies on shared defaults. Imagine a real file that starts with Host * carrying your standard IdentityFile and UpdateHostKeys yes, followed by narrow host aliases that only override HostName and User. OpenSSH can apply those defaults across matching hosts, but the editor evaluates each visible stanza on its own. A later host block may therefore look as if it lacks an identity file even though the live SSH client would inherit one. In that situation the warning is still useful as a reminder to inspect the structure, but it is not a final statement about runtime behavior.
A repeated key that is not automatically a mistake. Suppose a bastion entry has two LocalForward lines and two IdentityFile lines because you use multiple tunnels and fallback identities. The lint view marks repeated keys, and the de-duplication switch would keep only the last line for each repeated directive. That makes the page helpful for spotting complexity, but it also means you should avoid using de-duplication as a blanket cleanup button on multi-forward or multi-key host blocks.
No. The page has no server-side handler for parsing or export. Import, analysis, diffing, and file generation stay in the browser session.
Host *, Include, and Match the same way OpenSSH does?No. It can preserve visible non-host lines and it can count simple host-pattern matches, but it does not fully evaluate inherited defaults, conditional matching, or included files. Treat those parts of your config as context the editor helps you review, not logic it fully simulates.
The lint pass is conservative. It flags repeated directive names as something to review structurally. OpenSSH does allow multiple entries for some settings, including multiple identity files and multiple forwarding lines, so a duplicate warning is not automatically an error.
Because the editor keeps the last repeated key inside a host block when de-duplication is enabled. OpenSSH itself generally uses the first obtained value for most parameters, and some directives are intentionally repeatable. Review those hosts manually before using the switch.
No. It only means the visible directives did not trigger the editor's built-in checks. It does not verify host fingerprints, confirm remote policy, validate file paths, or evaluate included and inherited configuration.
Yes. The editor supports custom directive names, so it can still rebuild host blocks that use less common SSH client options.
HostHostNameIdentityFileStrictHostKeyCheckingProxyJumpLocalForward and RemoteForwardHost and Match behavior, repeated IdentityFile entries, forwarding semantics, and host-key checking rules.