{"id":43894292,"url":"https://github.com/dankraw/ssh-aliases","last_synced_at":"2026-02-06T17:14:25.238Z","repository":{"id":57525829,"uuid":"107787651","full_name":"dankraw/ssh-aliases","owner":"dankraw","description":"A tool for ~/.ssh/config generation","archived":false,"fork":false,"pushed_at":"2025-08-26T17:39:32.000Z","size":1477,"stargazers_count":50,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-26T23:26:35.948Z","etag":null,"topics":["golang","hcl","ssh","ssh-config"],"latest_commit_sha":null,"homepage":"","language":"Go","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/dankraw.png","metadata":{"files":{"readme":"README.md","changelog":null,"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,"zenodo":null}},"created_at":"2017-10-21T14:35:59.000Z","updated_at":"2025-08-26T17:39:36.000Z","dependencies_parsed_at":"2025-08-26T18:52:10.262Z","dependency_job_id":"2647fad0-5efb-4fe2-908d-28965b64dd2b","html_url":"https://github.com/dankraw/ssh-aliases","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/dankraw/ssh-aliases","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dankraw%2Fssh-aliases","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dankraw%2Fssh-aliases/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dankraw%2Fssh-aliases/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dankraw%2Fssh-aliases/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dankraw","download_url":"https://codeload.github.com/dankraw/ssh-aliases/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dankraw%2Fssh-aliases/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29169397,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-06T16:33:35.550Z","status":"ssl_error","status_checked_at":"2026-02-06T16:33:30.716Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["golang","hcl","ssh","ssh-config"],"created_at":"2026-02-06T17:14:24.509Z","updated_at":"2026-02-06T17:14:25.227Z","avatar_url":"https://github.com/dankraw.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ssh-aliases\n[![Go Report Card](https://goreportcard.com/badge/github.com/dankraw/ssh-aliases)](https://goreportcard.com/report/github.com/dankraw/ssh-aliases)\n\n`ssh-aliases` is a command line tool that brings ease to living with `~/.ssh/config`.\n\nIn short, `ssh-aliases`:\n* combines multiple [human friendly config files](#configuration-files) into a single `ssh` config file\n* is able to generate a list of hosts out of a single entry by using [expanding expressions](#expanding-expressions), \nlike `instance[1..3].example.com` or `[master|slave].example.com`\n* is able to generate aliases for provided (as an input file) lists of hosts [using regular expressions matching](#using-regular-expressions-to-match-existing-hostnames)\n* creates aliases for hosts by compiling [templates](#alias-templates)\n* allows multiple hosts reuse the same `ssh` configuration\n* is a single binary file\n\n## Table of contents\n\n* [Installation](#installation)\n* [Configuration files](#configuration-files)\n    * [Scanned directories](#scanned-directories)\n    * [Components](#components)\n        * [Host definitions](#host-definitions)\n        * [Config properties](#config-properties)\n            * [Extending configurations](#extending-configurations)\n        * [Variables](#variables)\n    * [Expanding hosts](#expanding-hosts)\n        * [Expanding expressions](#expanding-expressions)\n        * [Alias templates](#alias-templates)\n    * [Using regular expressions to match existing hostnames](#using-regular-expressions-to-match-existing-hostnames)\n    * [Tips and tricks](#tips-and-tricks)\n* [Usage (CLI)](#usage-cli)\n    * [`compile`](#compile---generating-configuration-for-ssh) - generating configuration for `ssh`\n    * [`list`](#list---listing-aliases-definitions) - listing aliases definitions\n* [License](#license)\n\n\n## Installation\n\n### Binary distribution\n\nBinary releases for Linux and MacOS can be found on [GitHub releases page](https://github.com/dankraw/ssh-aliases/releases).\n\n### Homebrew tap\n\nMacOS users can install `ssh-aliases` easily using [Homebrew](https://brew.sh):\n\n``` console\nbrew tap dankraw/ssh-aliases\nbrew install ssh-aliases\n```\n\n### Source code\n\nIf you are familiar with Go: \n\n``` console\ngo get github.com/dankraw/ssh-aliases\n```\n\nThere is a `Makefile`, so you can use it as well:\n\n``` console\nmake test # run tests\nmake fmt  # format code\nmake lint # run linters\nmake      # build binary to ./target/ssh-aliases\n```\n\n## Configuration files\n\n`ssh-aliases` is a tool for `~/.ssh/config` file generation. \nThe input for `ssh-aliases` are [HCL](https://github.com/hashicorp/hcl) config files. \nHCL was designed to be written and modified by humans. \nIn some way it is similar to JSON, but is more expressive and concise at the same time, \nallows using comments, etc. \n\nLooking at examples below will be enough to become familiar with HCL format.\n\n### Scanned directories\n\n`ssh-aliases` allows you to divide your `ssh` configuration into multiple files depending on your needs.\nWhen running `ssh-aliases` you point it to a directory (by default it's `~/.ssh_aliases`) \ncontaining any number of HCL config files. The directory will be scanned for files with `.hcl` extension.\nKeep in mind it does not scan recursively - child directories won't be considered.\n\n### Components\n\nA single config file may contain any number of components defined in it. \nCurrently there are three types of components:\n* [Host definitions](#host-definitions)\n* [Config properties](#config-properties)\n* [Variables](#variables)\n\n#### Host definitions\n\nA host definition consists of a `host` keyword and it's globally unique (among all scanned files) name.\nEach `host` should contain following attributes:\n* `hostname` - is a target hostname, possibly containing [expanding expressions](#expanding-hosts) \n   or it may be a [regular expression matching selected group of hosts](#using-regular-expressions-to-match-existing-hostnames)\n* `alias` - is an alias template for the destination hostname\n* `config` - an embedded [config properties](#config-properties) definition, or a name (a `string`) that points \nto existing properties definition in the same or any other configuration file\n\nAn example host definition looks like:\n\n``` hcl\nhost \"my-service\" {\n  hostname = \"instance[1..2].my-service.example.com\",\n  alias = \"myservice{#1}\"\n  config = {\n    user = \"ubuntu\"\n    identity_file = \"~/.ssh/my_service.pem\"\n    port = 22\n    // etc.\n  }\n}\n```\n\nor (when pointing an external config named `my-service-config`)\n\n``` hcl\nhost \"my-service\" {\n  hostname = \"instance[1..2].my-service.example.com\",\n  alias = \"myservice{#1}\"\n  config = \"my-service-config\"\n}\n```\n\nor (when using regular expression to match selected hosts from user input)\n\n```hcl\nhost \"my-service\" {\n  hostname = \"instance\\\\-(\\\\d+)\\\\.my\\\\-service\\\\-([a-z]+)\\\\..+dc1.+\",\n  alias = \"{#2}.myservice{#1}.dc1\"\n  config = \"my-service-config\"\n}\n```\n\n#### Config properties\n\nA config properties definition consists of a `config` keyword and it's globally unique (among all scanned files) name.\nIt's body is a list of properties that map to `ssh_config` keywords and their values. \nA complete list of ssh config keywords can be seen [here](https://linux.die.net/man/5/ssh_config) \nor listed via `man ssh_config` in your terminal.\n\nEach property may contain an underscore (`_`) in its keyword for clarity, \nall underscores are removed during config compilation, first character and all letters that follow underscores are capitalized - \nthis makes generated file easier to read. For example, `identity_file` will become `IdentityFile` in the destination config file.\nBy design `ssh_config` keywords are case insensitive, and their values are case sensitive.\n\nProvided properties are not validated by `ssh-aliases`, so it should work even if you have a custom built `ssh` command.\n\nAn example config properties definition may look like:\n\n``` hcl\nconfig \"some-config\" {\n  user = \"ubuntu\"\n  identity_file = \"id_rsa.pem\"\n  port = 22\n  // etc.\n}\n```\n\n##### Extending configurations\n\nA special property `_extend` can be used in order to include properties from other configurations.\nTop level properties override lower level properties. \n\n```hcl\nconfig \"top-level\" {\n  user = \"eden\"\n  _extend = \"lower-level\"\n  # port = 2222 (will be included from below configuration)\n  # ...\n}\n\nconfig \"lower-level\" {\n  user = \"helix\"\n  port = 2222\n  # etc.\n}\n```\n\nA single configuration may extend multiple configurations, in this case an array of configuration names should be provided as the `_extend` property.\n\n```hcl\nconfig \"top-level\" {\n  user = \"eden\"\n  _extend = [\"lower-level1\", \"lower-level2\"] \n  # configurations are included from left to right (and overridden in this order)\n  # port = 4444\n}\n\nconfig \"lower-level1\" {\n  user = \"helix\"\n  port = 2222\n  # etc.\n}\n\nconfig \"lower-level2\" {\n  user = \"torus\"\n  port = 4444\n  # etc.\n}\n```\n\n#### Variables\n\nVariables are declared in object blocks marked with `var` keyword. There may be many `var` blocks distributed along multiple files, but variable names have global scope, so each one can be declared only once.\n\nExample variables block may look like:\n\n```hcl\nvar {\n    dc1 = \"my.domain1.example.com\"\n    dc2 = \"some.other.domain2.net\"\n    keys {\n        service_a = \"/path/to/a_key.pem\"\n        service_b = \"/path/to/b_key.pem\"\n    }\n    nodes {\n      service_a = 5\n    }\n    users {\n      a = \"eden\"\n      b = \"helix\"\n    }\n}\n```\n\nVariables can be nested, their lookup names are flattened during processing with `.` separator.\nIn this example we have defined following variables: `dc1`, `dc2`, `keys.service_a`, `keys.service_b`, `nodes.service_a`, `users.a`, `users.b`.\n\nVariables can be used in:\n* Aliases \n* Hostnames\n* Config property values\n\nString interpolation with variables is done by using a `${name}` placeholder, for example:\n\n```hcl\nhost \"service-a\" {\n  hostname = \"instance[1..${nodes.service_a}].${dc1}\",\n  alias = \"myservice{#1}\"\n  config = {\n    user = \"${users.a}\"\n    identity_file = \"${keys.service_a}\"\n  }\n}\n```\n\n### Expanding hosts\n\nOne of the most important features of `ssh-aliases` is *hosts expansion*.\nIt's a mechanism of generating multiple `Host ...` entries in the destination `ssh_config` out of a single [host definition](#host-definitions).\nIt is done by using *expanding expressions* in hostnames and compiling host aliases from templates.\n\n#### Expanding expressions\n\nThere are two types of *expanding expressions* available:\n* ranges\n* sets\n\nA **range** is represented as `[m..n]`, where `m` and `n` are positive integers that `m \u003c n`. \nFor example, a hostname `instance[1..3].example.com` will be expanded to:\n\n``` console\ninstance1.example.com\ninstance2.example.com\ninstance3.example.com\n```\n\nA **set** is represented as `[a]`, `[a|b]`, `[a|b|c]` and so on, \nwhere `a`, `b`, `c`... are some arbitrary strings of characters allowed in hostnames.\nFor example, a hostname `server.[dev|test|prod].example.com` will be expanded to:\n\n``` console\nserver.dev.example.com\nserver.test.example.com\nserver.prod.example.com\n```\n\nOf course ranges and sets can be used together multiple times each. \nA final result will be a [cartesian product](https://en.wikipedia.org/wiki/Cartesian_product) of all expanding expressions provided.\nFor example, a hostname `server[1..2].[dev|test].example.com` would be expanded to:\n\n``` console\nserver1.dev.example.com\nserver1.test.example.com\nserver2.dev.example.com\nserver2.test.example.com\n```\n\n#### Alias templates\n\nEach generated `Host ...` entry needs to have an alias that is provided in [host definition](#host-definitions). \nIf hostnames are [expanded](#expanding-expressions) it is required to provide **placeholders** \nfor all expanding expressions used. Otherwise `ssh-aliases` would generate \nthe same alias for multiple hostnames, and that simply makes no sense.\n\nAn expanding expression placeholder is represented as `{#n}`, where `n=1,2...k`, \n`n` points the `n-th` expression used in hostname (sequence from left to right) \nand so `k` is the number of expanding expressions used in total. \n\nFor example, `{#1}` points the first expression used in hostname, `{#2}` points the second, and so on.\n\nIf we look at the hostname example from above section `server[1..2].[dev|test].example.com`, we have two expressions used:\n1. `[1..2]`\n2. `[dev|test]`\n\nWe can declare an alias template like `{#2}.server{#1}`, \nwhich would compile following aliases for the generated hostnames:\n\n``` console\ndev.server1\ntest.server1\ndev.server2\ntest.server2\n```\n\n### Using regular expressions to match existing hostnames\n\nAlternatively, instead of defining [expanding expressions](#expanding-expressions) by hand, user can provide \na list of existing hosts as an input file and define regular expressions that match selected groups of hosts, \n`ssh-aliases` will generate aliases and hook proper configurations to matched hosts.\n\nFor example, the user is able to fetch from some kind of cloud service API or \n[an asset management system](https://github.com/allegro/ralph)\n(or will just `cat ~/.ssh/known_hosts | cut -f 1 -d ',' | cut -f 1 -d ' '`) a list of nodes that is allowed to log into:\n\n```\ninstance1.my-service-evo.example.com\ninstance1.my-service-dev.example.com\ninstance1.my-service-test.example.com\ninstance2.my-service-test.example.com\ninstance1.my-service-prod.example.com\ninstance2.my-service-prod.example.com\ninstance3.my-service-prod.example.com\n```\n\nIf there are patterns existing between some of these hosts, a regular expression can be defined to match them, \nin this case `\"instance(\\\\d+)\\\\.my\\\\-service\\\\-(dev|prod|test)\\\\..+\"`. \nNote there are two groups being captured `(\\\\d+)` for instance number and `(dev|prod|test)` for host environment \n(we want to omit the experimental `evo` environment).\nIn order to place the captured group value into the alias use the `{#n}` placeholder, \nsame as for [expanding expressions](#alias-templates).\n\n[Host definitions](#host-definitions) with a hostname containing at least a single group capturing statement \n(starting with a \"`(`\" parenthesis) are considered as regexp hosts type, and [expanding expressions](#expanding-expressions) \nare not applied to them. Of course, both types of hosts can be mixed in the same `ssh-aliases` configuration (file or directory).\n\n```hcl\nhost \"dc1-services\" {\n  hostname = \"instance(\\\\d+)\\\\.my\\\\-service\\\\-(dev|prod|test)\\\\..+\"\n  alias = \"host{#1}.{#2}\"\n  config {\n    user = \"abc\"\n    identity_file = \"~/.ssh/key.pem\"\n  }\n}\n```\n\n[Compiling the aliases](#compile---generating-configuration-for-ssh) with `--hosts-file /path/to/hosts_file.txt` option will generate:\n\n```\nHost host1.dev\n     HostName instance1.my-service-dev.example.com\n     IdentityFile ~/.ssh/key.pem\n     User abc\n\nHost host1.test\n     HostName instance1.my-service-test.example.com\n     IdentityFile ~/.ssh/key.pem\n     User abc\n\nHost host2.test\n     HostName instance2.my-service-test.example.com\n     IdentityFile ~/.ssh/key.pem\n     User abc\n\nHost host1.prod\n     HostName instance1.my-service-prod.example.com\n     IdentityFile ~/.ssh/key.pem\n     User abc\n\nHost host2.prod\n     HostName instance2.my-service-prod.example.com\n     IdentityFile ~/.ssh/key.pem\n     User abc\n\nHost host3.prod\n     HostName instance3.my-service-prod.example.com\n     IdentityFile ~/.ssh/key.pem\n     User abc\n```\n\n[Printing the list of aliases](#list---listing-aliases-definitions) accordingly would print:\n\n```\nconfig.hcl (1):\n\n dc1-services (6):\n  host1.dev: instance1.my-service-dev.example.com\n  host1.test: instance1.my-service-test.example.com\n  host2.test: instance2.my-service-test.example.com\n  host1.prod: instance1.my-service-prod.example.com\n  host2.prod: instance2.my-service-prod.example.com\n  host3.prod: instance3.my-service-prod.example.com\n\n```\n\n\n### Tips and tricks\n\n* Generated `ssh_config` configuration can be used not only with `ssh` command, but with other OpenSSH client commands, like `scp` and `sftp`\n* Multiple alias templates may be provided for the same host definition, for example:\n\n```hcl\nhost \"my-service\" {\n  hostname = \"instance[1..2].myservice.example.com\",\n  alias = \"myservice{#1} ms{#1}\" # separated with space\n  config = \"some-config\"\n}\n```\n\n* `ssh_config` (v7.2+) ships with `Include` directive ([see docs](https://man.openbsd.org/ssh_config.5#Include)) that can be used to include other files. This can be useful for mixing `ssh-aliases` generated configs with pure `ssh_config` files:\n\n```ssh_config\nInclude path/to/ssh-aliases/generated/ssh_config\n\n# below some legacy ssh config that one day may be migrated to ssh-aliases\nHost myservice\n    HostName myservice.example.com\n    User myself\n# ...\n```\n\n* `config` properties are optional when `alias` is provided:\n\n```hcl\nhost \"example\" {\n    hostname = \"my.service[1..2].example.com\"\n    alias = \"myservice{#1}\"\n}\n```\n\n* `alias` (or `hostname` when `alias` is provided) is optional when `config` properties are provided. This can be useful for creating wildcard (`*`) configurations that match any host:\n\n```hcl\nhost \"all-hosts\" {\n    hostname = \"*\" # or alias = \"*\"\n    config {\n        # ...\n    }\n}\n```\n\n## Usage (CLI)\n\nRun `ssh-aliases --help` to see available options of the `ssh-aliases` command line interface (CLI).\n\nIn general, there are only two commands available:\n* `compile` - prints (or saves to a file) compiled `ssh` config\n* `list` - prints preview of generates aliases and hostnames\n\nBoth commands share the same global option: `--scan` or `-s` which should point to the directory \ncontaining [input config files](#configuration-files).\nIf omitted, `ssh-aliases` will look for `~/.ssh_aliases` directory.\nThis option should be passed *before* the selected command name.\n\n### `compile` - generating configuration for `ssh`\n\n`compile` is the primary command in `ssh-aliases` - it combines together all input config files \nand compiles configuration for `ssh`.  \n\nOptions for `compile`\n\n* `--hosts-file` - input hosts file for regexp compilation (each hostname in new line)\n* `--save` - adding this option makes `ssh-aliases` save the output to the file instead of printing to `stdout`, \nasks for confirmation if the file exists (unless `--force` is used) and overwrites its contents if accepted\n* `--file \u003cPATH\u003e` - when using `--save` it tells where should the file be saved, defaults to `~/.ssh/config`\n* `--force` - when using `--save` it will overwrite possibly existing file without confirmation\n* `--help` - shows command usage\n\nExample command run with all options provided:\n\n```console\n$ ssh-aliases --scan ~/my_custom_dir compile --save --file ~/.ssh/ssh_aliases_config --force \n```\n\nNow, let's suppose we have `./examples/readme` directory that contains 3 files:\n\n```hcl\n# ./example/readme/example_service_1.hcl\nhost \"abc\" {\n  hostname = \"node[1..2].abc.[dev|test].example.com\"\n  alias = \"{#2}.abc{#1}\"\n  config = \"abc-config\"\n}\n\nconfig \"abc-config\" {\n  user = \"ubuntu\"\n  identity_file = \"${keys.abc}\"\n  port = 22\n}\n```\n\n```hcl\n# ./example/readme/example_service_2.hcl\nhost \"other\" {\n  hostname = \"other[1..2].example.com\"\n  alias = \"other{#1}\"\n  config {\n    user = \"lurker\"\n    identity_file = \"${keys.other}\"\n    port = 22\n  }\n}\n```\n\n```hcl\n# ./example/readme/variables.hcl\nvar {\n    keys {\n        abc = \"~/.ssh/abc.pem\"\n        other = \"~/.ssh/other.pem\"\n    }\n}\n```\n\nLet's run `compile` command for that directory:\n\n``` console\n$ ssh-aliases --scan ./examples/readme compile\n```\n\n`ssh-aliases` will print:\n\n``` console\nHost dev.abc1\n     HostName node1.abc.dev.example.com\n     IdentityFile ~/.ssh/abc.pem\n     Port 22\n     User ubuntu\n\nHost dev.abc2\n     HostName node2.abc.dev.example.com\n     IdentityFile ~/.ssh/abc.pem\n     Port 22\n     User ubuntu\n\nHost test.abc1\n     HostName node1.abc.test.example.com\n     IdentityFile ~/.ssh/abc.pem\n     Port 22\n     User ubuntu\n\nHost test.abc2\n     HostName node2.abc.test.example.com\n     IdentityFile ~/.ssh/abc.pem\n     Port 22\n     User ubuntu\n\nHost other1\n     HostName other1.example.com\n     IdentityFile ~/.ssh/other.pem\n     Port 22\n     User lurker\n\nHost other2\n     HostName other2.example.com\n     IdentityFile ~/.ssh/other.pem\n     Port 22\n     User lurker\n```\n\n### `list` - listing aliases definitions\n\n`list` command should be used to check correctness of declared [hostname patterns](#host-definitions) \nand [alias templates](#alias-templates). \nIt will print a concise list of compiled results, yet omitting linked [config properties](#config-properties). \n\nOptions for `list`\n* `--hosts-file` - input hosts file for regexp compilation (each hostname in new line)\n\nFor example, let's run `list` for `./examples/readme` directory from previous paragraph:\n \n``` console \n$ ssh-aliases --scan ./examples/readme list\n```\nThe printed result will be:\n\n``` console\nreadme/example_service_1.hcl (1):\n\n abc (4):\n  dev.abc1: node1.abc.dev.example.com\n  dev.abc2: node2.abc.dev.example.com\n  test.abc1: node1.abc.test.example.com\n  test.abc2: node2.abc.test.example.com\n\nreadme/example_service_2.hcl (1):\n\n other (2):\n  other1: other1.example.com\n  other2: other2.example.com\n```\n\n## License\n\n`ssh-aliases` is published under [MIT License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdankraw%2Fssh-aliases","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdankraw%2Fssh-aliases","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdankraw%2Fssh-aliases/lists"}