{"id":14155529,"url":"https://github.com/cyjake/ssh-config","last_synced_at":"2026-02-26T08:57:32.552Z","repository":{"id":25679669,"uuid":"29115613","full_name":"cyjake/ssh-config","owner":"cyjake","description":"📟 SSH config parser and stringifier","archived":false,"fork":false,"pushed_at":"2025-02-05T06:18:45.000Z","size":151,"stargazers_count":81,"open_issues_count":1,"forks_count":20,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-01T05:34:44.606Z","etag":null,"topics":["javascript","ssh-config-parser"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cyjake.png","metadata":{"files":{"readme":"Readme.md","changelog":"History.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-01-12T02:47:35.000Z","updated_at":"2025-03-30T00:41:37.000Z","dependencies_parsed_at":"2024-06-18T13:39:17.673Z","dependency_job_id":"00762a75-2286-41b3-a017-6695abcf652a","html_url":"https://github.com/cyjake/ssh-config","commit_stats":{"total_commits":117,"total_committers":11,"mean_commits":"10.636363636363637","dds":"0.24786324786324787","last_synced_commit":"be960c2eb040c16a58c33d2bcf8b7af4c30d5d7c"},"previous_names":[],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cyjake%2Fssh-config","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cyjake%2Fssh-config/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cyjake%2Fssh-config/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cyjake%2Fssh-config/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cyjake","download_url":"https://codeload.github.com/cyjake/ssh-config/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247801169,"owners_count":20998339,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","ssh-config-parser"],"created_at":"2024-08-17T08:03:47.044Z","updated_at":"2026-02-26T08:57:32.544Z","avatar_url":"https://github.com/cyjake.png","language":"TypeScript","funding_links":[],"categories":["javascript"],"sub_categories":[],"readme":"# SSH Config Parser \u0026 Stringifier\n\n[![NPM Downloads](https://img.shields.io/npm/dm/ssh-config.svg?style=flat)](https://www.npmjs.com/package/ssh-config)\n[![NPM Version](http://img.shields.io/npm/v/ssh-config.svg?style=flat)](https://www.npmjs.com/package/ssh-config)\n![JSR Version](https://img.shields.io/jsr/v/%40cyjake/ssh-config)\n[![Build Status](https://travis-ci.org/cyjake/ssh-config.svg)](https://travis-ci.org/cyjake/ssh-config)\n[![Deno CI](https://github.com/cyjake/ssh-config/actions/workflows/deno.yml/badge.svg)](https://github.com/cyjake/ssh-config/actions/workflows/deno.yml)\n[![Node CI](https://github.com/cyjake/ssh-config/actions/workflows/nodejs.yml/badge.svg)](https://github.com/cyjake/ssh-config/actions/workflows/nodejs.yml)\n[![codecov](https://codecov.io/gh/cyjake/ssh-config/branch/master/graph/badge.svg?token=RMyTgcL8Kg)](https://codecov.io/gh/cyjake/ssh-config)\n\n## Usage\n\n```js\nconst SSHConfig = require('ssh-config')\n\nconst config = SSHConfig.parse(`\n  IdentityFile ~/.ssh/id_rsa\n\n  Host tahoe\n    HostName tahoe.com\n\n  Host walden\n    HostName waldenlake.org\n\n  Host *\n    User keanu\n    ForwardAgent true\n`)\n\nexpect(config).to.eql(\n  [ { \"param\": \"IdentityFile\",\n      \"value\": \"~/.ssh/id_rsa\" },\n    { \"param\": \"Host\",\n      \"value\": \"tahoe\",\n      \"config\":\n        [ { \"param\": \"HostName\",\n            \"value\": \"tahoe.com\" } ] },\n    { \"param\": \"Host\",\n      \"value\": \"walden\",\n      \"config\":\n        [ { \"param\": \"HostName\",\n            \"value\": \"waldenlake.org\" } ] },\n    { \"param\": \"Host\",\n      \"value\": \"*\",\n      \"config\":\n        [ { \"param\": \"User\",\n            \"value\": \"keanu\" },\n          { \"param\": \"ForwardAgent\",\n            \"value\": \"true\" } ] } ]\n)\n\n// Change the HostName in the Host walden section\nconst section = config.find({ Host: 'walden' })\n\nfor (const line of section.config) {\n  if (line.param === 'HostName') {\n    line.value = 'waldenlake.org'\n    break\n  }\n}\n\n// The original whitespaces and comments are preserved.\nconsole.log(SSHConfig.stringify(config))\n// console.log(config.toString())\n```\n\n### Iterating over Sections\n\nOne needs to iterate over ssh configs mostly because of two reasons.\n\n- to `.find` the corresponding section and modify it, or\n- to `.compute` the ssh config about certain `Host`.\n\n\n### `.compute` Parameters by Host\n\nYou can use `config.compute` method to compute applied parameters of certain host.\n\n```js\nexpect(config.compute('walden')).to.eql({\n  IdentityFile: [\n    '~/.ssh/id_rsa'\n  ],\n  Host: 'walden',\n  HostName: 'waldenlake.org',\n  User: 'nil',\n  ForwardAgent: 'true'\n})\n```\n\n**NOTICE** According to [ssh_config(5)][ssh_config], the first obtained\nparameter value will be used. So we cannot override existing parameters. It is\nsuggested that the general settings shall be at the end of your config file.\n\nThe `IdentityFile` parameter always contain an array to make possible multiple\n`IdentityFile` settings to be able to coexist.\n\n#### Case-Insensitive Matching\n\nOpenSSH treats configuration directives case-insensitively. By default, `compute()`\npreserves the original case from the config file. To normalize directive names to\nlowercase (matching OpenSSH behavior), use the `ignoreCase` option:\n\n```js\nconst config = SSHConfig.parse(`\n  Host example\n    hOsTnaME 1.2.3.4\n    USER admin\n`)\n\n// Default - preserves original case\nconfig.compute('example')\n// =\u003e { hOsTnaME: '1.2.3.4', USER: 'admin' }\n\n// With ignoreCase - lowercase to match OpenSSH\nconfig.compute('example', { ignoreCase: true })\n// =\u003e { hostname: '1.2.3.4', user: 'admin' }\n```\n\n### `.find` sections by Host or Match\n\n**NOTICE**: This method is provided to find the corresponding section in the\nparsed config for config manipulation. It is NOT intended to compute config\nof certain Host. For latter case, use `.compute(host)` instead.\n\nTo ditch boilerplate codes like the for loop shown earlier, we can use the\n`.find(opts)` available in the parsed config object.\n\n```js\nconfig.find({ Host: 'example1' })\n// or the ES2015 Array.prototype.find\nconfig.find(line =\u003e line.param == 'Host' \u0026\u0026 line.value == 'example1')\n```\n\n### `.remove` sections by Host / Match or function\n\nTo remove sections, we can pass the section to `.remove(opts)`.\n\n```js\nconfig.remove({ Host: 'example1' })\n// or the ES2015 Array.prototype.find\nconfig.remove(line =\u003e line.param == 'Host' \u0026\u0026 line.value == 'example1')\n```\n\n### `.append` sections\n\nSince the parsed config is a sub class of Array, you can append new sections with methods like `.push` or `.concat`.\n\n```js\nconfig.push(...SSHConfig.parse(`\nHost ness\n  HostName lochness.com\n  User dinosaur\n`))\n\nexpect(config.find({ Host: '*' })).to.eql(\n  { \"param\": \"Host\",\n    \"value\": \"ness\",\n    \"config\":\n     [ { \"param\": \"HostName\",\n         \"value\": \"lochness.com\" } ] }\n)\n```\n\nIf the section to append is vanilla JSON, `.append` is what you need.\n\n```js\nconst config = new SSHConfig()\n\nconfig.append({\n  Host: 'ness',\n  HostName: 'lochness.com',\n  User: 'dinosaur'\n})\n\nSSHConfig.stringify(config)\n// =\u003e\n// Host ness\n//   HostName lochness.com\n//   User dinosaur\n```\n\n### `.prepend` sections\n\nBut appending options to the end of the config isn't very effective if your config is organizated per the recommendations of ssh_config(5) that the generic options are at at the end of the config, such as:\n\n```\nHost ness\n  HostName lochness.com\n  User dinosaur\n\nIdentityFile ~/.ssh/id_rsa\n```\n\nThe config could get messy if you put new options after the line of `IdentityFile`. To work around this issue, it is recommended that `.prepend` should be used instead. For the example above, we can prepend new options at the beginning of the config:\n\n```js\nconfig.prepend({\n  Host: 'tahoe',\n  HostName 'tahoe.com',\n})\n```\n\nThe result would be:\n\n```\nHost tahoe\n  HostName tahoe.com\n\nHost ness\n  HostName lochness.com\n  User dinosaur\n\nIdentityFile ~/.ssh/id_rsa\n```\n\nIf there are generic options at the beginning of the config, and you'd like the prepended section put before the first existing section, please turn on the second argument of `.prepend`:\n\n```js\nconfig.prepend({\n  Host: 'tahoe',\n  HostName 'tahoe.com',\n}, true)\n```\n\nThe result would be like:\n\n```\nIdentityFile ~/.ssh/id_rsa\n\nHost tahoe\n  HostName tahoe.com\n\nHost ness\n  HostName lochness.com\n  User dinosaur\n```\n\n## References\n\n- [ssh_config(5)][ssh_config]\n- [ssh_config(5)][ssh_config_die]\n- [ssh_config(5) OpenBSD][ssh_config_openbsd]\n- http://en.wikibooks.org/wiki/OpenSSH/Client_Configuration_Files#.7E.2F.ssh.2Fconfig\n- http://stackoverflow.com/questions/10197559/ssh-configuration-override-the-default-username\n\n\n[ssh_config]: https://www.freebsd.org/cgi/man.cgi?query=ssh_config\u0026sektion=5\n[ssh_config_die]: http://linux.die.net/man/5/ssh_config\n[ssh_config_openbsd]: http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man5/ssh_config.5?query=ssh_config\u0026arch=i386\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcyjake%2Fssh-config","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcyjake%2Fssh-config","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcyjake%2Fssh-config/lists"}