{"id":13499324,"url":"https://github.com/moul/assh","last_synced_at":"2026-01-30T22:12:50.907Z","repository":{"id":2107606,"uuid":"3049190","full_name":"moul/assh","owner":"moul","description":":computer: make your ssh client smarter","archived":false,"fork":false,"pushed_at":"2025-05-04T21:12:24.000Z","size":24382,"stargazers_count":3128,"open_issues_count":125,"forks_count":157,"subscribers_count":51,"default_branch":"master","last_synced_at":"2025-05-04T22:29:31.570Z","etag":null,"topics":["automation","config","config-management","devops","proxy","ssh"],"latest_commit_sha":null,"homepage":"https://manfred.life/assh","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/moul.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["moul"],"patreon":"moul","open_collective":"moul","custom":["https://manfred.life/donate"]}},"created_at":"2011-12-25T21:15:04.000Z","updated_at":"2025-04-29T22:09:39.000Z","dependencies_parsed_at":"2024-01-27T03:40:07.516Z","dependency_job_id":"2837c5d0-8ecd-437a-9514-8162b691748f","html_url":"https://github.com/moul/assh","commit_stats":{"total_commits":587,"total_committers":43,"mean_commits":"13.651162790697674","dds":"0.28960817717206133","last_synced_commit":"869f9789172e5c778ced5121ca4ac5abdf29bd57"},"previous_names":["moul/advanced-ssh-config"],"tags_count":72,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moul%2Fassh","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moul%2Fassh/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moul%2Fassh/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moul%2Fassh/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/moul","download_url":"https://codeload.github.com/moul/assh/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254042308,"owners_count":22004896,"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":["automation","config","config-management","devops","proxy","ssh"],"created_at":"2024-07-31T22:00:32.214Z","updated_at":"2026-01-30T22:12:50.877Z","avatar_url":"https://github.com/moul.png","language":"Go","readme":"# assh\n\n[![GoDoc](https://img/shields.io/static/v1?label=godoc\u0026message=reference\u0026color=blue)](https://pkg.go.dev/moul.io/assh/v2)\n[![Financial Contributors on Open Collective](https://opencollective.com/assh/all/badge.svg?label=financial+contributors)](https://opencollective.com/assh) ![License](https://img.shields.io/github/license/moul/assh.svg)\n[![CircleCI](https://circleci.com/gh/moul/assh.svg?style=svg)](https://circleci.com/gh/moul/assh)\n[![GitHub release](https://img.shields.io/github/release/moul/assh.svg)](https://github.com/moul/assh/releases)\n[![Go Report Card](https://goreportcard.com/badge/moul.io/assh)](https://goreportcard.com/report/moul.io/assh)\n\n\u003cimg src=\"https://raw.githubusercontent.com/moul/assh/master/resources/assh.png\" width=\"400\" /\u003e\n\n## Overview\n\nA *transparent wrapper* that adds support for **regex**, **aliases**, **gateways**, **dynamic hostnames**, **graphviz**, **json output**, **yaml configuration**, and more to **SSH**.\n\n[lib-ssh](https://www.libssh.org) wraps `assh` as a [ProxyCommand](https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Proxies_and_Jump_Hosts#ProxyCommand_with_Netcat); it means that it works seamlessly with:\n\n  * [ssh](http://www.openbsd.org/cgi-bin/man.cgi?query=ssh\u0026sektion=1)\n  * [scp](http://www.openbsd.org/cgi-bin/man.cgi?query=scp\u0026sektion=1)\n  * [rsync](http://linuxcommand.org/man_pages/rsync1.html)\n  * [git](https://www.kernel.org/pub/software/scm/git/docs/)\n  * Desktop applications depending on `lib-ssh` or `ssh` (i.e., [Tower](http://www.git-tower.com), [Atom.io](https://atom.io), [SSH Tunnel Manager](http://projects.tynsoe.org/fr/stm/))\n\nFor specific examples, see [3rd Party Integration](#3rd-party-integration)\n\n## Features\n\n### Configuration features\n\n  * **regex** support\n  * **aliases** `gate` -\u003e `gate.domain.tld`\n  * **gateways** -\u003e transparent ssh connection chaining\n  * **includes**: split configuration in multiple files, note that OpenSSH as of v7.3 has [native support for this](https://www.openssh.com/txt/release-7.3)\n  * **local command execution**: finally the reverse of **RemoteCommand**\n  * **templates**: equivalent to host but you can't connect directly to a template, perfect for inheritance\n  * **inheritance**: make hosts inherits from host hosts or templates\n  * **variable expansion**: resolve variables from the environment\n  * **smart proxycommand**: RAW tcp connection when possible with `netcat` and `socat` as default fallbacks\n  * **rate limit**: configure a per-host or global rate-limiting\n  * **JSON output**\n  * **[Graphviz](http://www.graphviz.org/)**: graphviz reprensentation of the hosts\n\n### Using Gateway from command line\n\n*assh* can use the [ProxyCommand with netcat](https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Proxies_and_Jump_Hosts#ProxyCommand_with_Netcat) feature of OpenSSH **transparently** and without the pain of using extended configuration.\n\nConnect to `hosta` using `hostb` as a gateway.\n\n```mermaid\nflowchart \n    direction TB\n\n    y[you]\n    a[hosta]\n    b[hostb]\n    fw((firewall))\n\n    style fw fill:#f00,color:#fff\n\n    y ==x fw\n    fw .-\u003e a\n    \n    y --\u003e b\n    b --\u003e a\n\n```\n\n```console\n$ ssh hosta/hostb\nuser@hosta $\n```\n\nEquivalent to `ssh -o ProxyCommand=\"ssh hostb nc %h %p\" hosta`\n\n---\n\nConnect to `hosta` using `hostb` as a gateway using `hostc` as a gateway.\n\n```mermaid\nflowchart \n    direction TB\n\n    y[you]\n    a[hosta]\n    b[hostb]\n    c[hostc]\n    fw((firewall))\n\n    style fw fill:#f00,color:#fff\n\n    y ==x fw\n    fw ..-\u003e a\n    \n    y --\u003e c\n    c --\u003e b\n    b --\u003e a\n```\n\n```console\n$ ssh hosta/hostb/hostc\nuser@hosta $\n```\n\nEquivalent to `ssh -o ProxyCommand=\"ssh -o ProxyCommand='ssh hostc nc %h %p' hostb nc %h %p\" hosta`\n\n### Using Gateways from configuration file\n\nYou can define an equivalent of the [\"ProxyCommand with netcat\"](https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Proxies_and_Jump_Hosts#ProxyCommand_with_Netcat) feature of OpenSSH, with a simpler syntax, more advanced workflows, and a unique fallback feature.\n\nLet's consider the following `assh.yml` file\n```yaml\nhosts:\n  hosta:\n    Hostname: 1.2.3.4\n\n  hostb:\n    Hostname: 5.6.7.8\n    Gateways: hosta\n\n  hostc:\n    Hostname: 9.10.11.12\n    Gateways: hostb\n\n  hostd:\n    Hostname: 13.14.15.16\n    GatewayConnectTimeout: 2\n    Gateways:\n    - direct\n    - hosta\n```\n\n  * `ssh hosta` -\u003e `ssh 1.2.3.4`\n  * `ssh hostb` -\u003e `ssh -o ProxyCommand=\"ssh hostb nc %h %p\" hosta`\n  * `ssh hostc` -\u003e `ssh -o ProxyCommand=\"ssh -o ProxyCommand='ssh hostc nc %h %p' hostb nc %h %p\" hosta`\n  * `ssh hostd` -\u003e\n    * assh will try to `ssh 13.14.15.16`\n    * then, fallback on `ssh -o ProxyCommand=\"ssh hostd nc %h %p\" hosta`\n    * this method allows you to have the best performances when it is possible, but ensure your commands will work if you are outside of your company for instance\n\n### Under the hood features\n\n  * Automatically regenerates `~/.ssh/config` file when needed\n  * Inspect parent process to determine log level (if you use `ssh -vv`, **assh** will automatically run in debug mode)\n  * Automatically creates `ControlPath` directories so you can use *slashes* in your `ControlPath` option, can be enabled with the `ControlMasterMkdir: true` configuration in host or globally.\n\n### Hooks\n\n#### Events\n\n##### BeforeConnect\n\n`BeforeConnect` is called just before `assh` tries to connect to the remote SSH port.\n\nNote: `BeforeConnect` will be called for each SSH connection; if you use multiple gateways, it will be called for each gateways until one succeed to connect.\n\n---\n\nExample of Golang template variables:\n\n```golang\n// Host: http://godoc.org/moul.io/assh/pkg/config/#Host\n{{.Host.Name}}                                  //  localhost\n{{.Host.HostName}}                              //  127.0.0.1\n{{.Host.Port}}                                  //  22\n{{.Host.User}}                                  //  moul\n{{.Host.Prototype}}                             //  moul@127.0.0.1:22\n{{.Host}}                                       //  {\"HostName\":\"localhost\",\"Port\":22\",\"User\":\"moul\",\"ControlPersist\":\"yes\",...}\n{{printf \"%s:%s\" .Host.HostName .Host.Port}}    //  localhost:22\n```\n\n##### OnConnect\n\n`OnConnect` is called as soon as assh is connected to the remote SSH port.\n\nNote: `OnConnect` is not aware of the authentication process and will always be raised.\n\n---\n\nExample of Golang template variables:\n\n```golang\n// Host: http://godoc.org/moul.io/assh/pkg/config/#Host\n{{.Host.Name}}                                  //  localhost\n{{.Host.HostName}}                              //  127.0.0.1\n{{.Host.Port}}                                  //  22\n{{.Host.User}}                                  //  moul\n{{.Host.Prototype}}                             //  moul@127.0.0.1:22\n{{.Host}}                                       //  {\"HostName\":\"localhost\",\"Port\":22\",\"User\":\"moul\",\"ControlPersist\":\"yes\",...}\n{{printf \"%s:%s\" .Host.HostName .Host.Port}}    //  localhost:22\n\n// Stats: http://godoc.org/moul.io/assh/pkg/commands/#ConnectionStats\n{{.Stats.ConnectedAt}}                           //  2016-07-20 11:19:23.467900594 +0200 CEST\n```\n\n##### OnConnectError\n\n`OnConnectError` is called when `assh` fails to open a new TCP connection.\n\n---\n\nExample of Golang template variables:\n\n```golang\n// Host: http://godoc.org/moul.io/assh/pkg/config/#Host\n{{.Host.Name}}                                  //  localhost\n{{.Host.HostName}}                              //  127.0.0.1\n{{.Host.Port}}                                  //  22\n{{.Host.User}}                                  //  moul\n{{.Host.Prototype}}                             //  moul@127.0.0.1:22\n{{.Host}}                                       //  {\"HostName\":\"localhost\",\"Port\":22\",\"User\":\"moul\",\"ControlPersist\":\"yes\",...}\n{{printf \"%s:%s\" .Host.HostName .Host.Port}}    //  localhost:22\n\n// Error\n{{.Error}}                                      //  dial tcp: lookup localhost: no such host\n```\n\n##### OnDisconnect\n\n`OnDisconnect` is called as the assh socket is closed.\n\n**warning**: if you don't see a notification when closing an SSH connection, then you probably have `ControlMaster` configured; `OnDisconnect` is not linked to the `ssh` program but to its **socket** which may stay alive even after exiting the `ssh` program.\n\n---\n\nExample of Golang template variables:\n\n```golang\n// Host: http://godoc.org/moul.io/assh/pkg/config/#Host\n{{.Host.Name}}                                  //  localhost\n{{.Host.HostName}}                              //  127.0.0.1\n{{.Host.Port}}                                  //  22\n{{.Host.User}}                                  //  moul\n{{.Host.Prototype}}                             //  moul@127.0.0.1:22\n{{.Host}}                                       //  {\"HostName\":\"localhost\",\"Port\":22\",\"User\":\"moul\",\"ControlPersist\":\"yes\",...}\n{{printf \"%s:%s\" .Host.HostName .Host.Port}}    //  localhost:22\n\n// Stats: http://godoc.org/moul.io/assh/pkg/commands/#ConnectionStats\n{{.Stats.ConnectedAt}}                           //  2016-07-20 11:19:23.467900594 +0200 CEST\n{{.Stats.WrittenBytes}}                          //  3613\n{{.Stats.WrittenBytesHuman}}                     //  3.6kb\n{{.Stats.DisconnectAt}}                          //  2016-07-20 11:19:29,520515792 +0200 CEST\n{{.Stats.ConnectionDuration}}                    //  6.052615198s\n{{.Stats.ConnectionDurationHuman}}               //  6s\n{{.Stats.AverageSpeed}}                          //  596.933bps\n{{.Stats.AverageSpeedHuman}}                     //  3.4kb/s\n```\n\n##### BeforeConfigWrite\n\n`BeforeConfigWrite` is called just before `assh` rewrite the `~/.ssh/config` file.\n\n---\n\nExample of Golang template variables:\n\n```golang\n{{.SSHConfigPath}}                               // ~/.ssh/config\n```\n\n#### Hooks drivers\n\n##### Exec driver\n\nExec driver uses [Golang's template system](https://golang.org/pkg/text/template/) to execute a shell command\n\nUsage: `exec \u003cbinary\u003e [args...]`\n\n```yaml\ndefaults:\n  Hooks:\n    OnConnect: exec echo '{{.Host}}' | jq .\n# executes: `echo '{\"HostName\":\"localhost\",\"Port\":\"22\",\"User\":\"moul\",\"ControlPersist\":\"yes\",...}' | jq .\n# which results in printing a pretty JSON of the host\n# {\n#   \"HostName\": \"localhost\",\n#   \"Port\": \"22\",\n#   \"User\": \"moul\",\n#   \"ControlPersist\": \"yes\",\n#   ...\n# }\n```\n\n```yaml\ndefaults:\n  Hooks:\n    OnConnect: exec echo 'New SSH connection to {{.Host.Prototype}}.' | mail -s \"SSH connection journal\" m+assh@42.am\n# send an email with the connection prototype\n```\n\n```yaml\ndefaults:\n  Hooks:\n    BeforeConfigWrite: exec cp {{.SSHConfigPath}} {{.SSHConfigPath}}.backup\n# make a copy of ~/.ssh/config before being rewritten\n```\n\n```yaml\ndefaults:\n  Hooks:\n    AfterConfigWrite: 'exec echo \"# date: `date`\" \u003e\u003e {{.SSHConfigPath}}'\n# Append a comment with the compilation date to the generated ~/.ssh/config file\n```\n\n```yaml\ndefaults:\n  Hooks:\n  AfterConfigWrite: 'exec cat /path/to/my/provider/generated/.ssh/config \u003e\u003e {{.SSHConfigPath}}'\n# Append another .ssh/config file to the generated .ssh/config file\n```\n\n---\n\nThe `exec` commands are blocking, a new driver for background tasks is planned. For now, you can run a job in background like this:\n\n```yaml\ndefaults:\n  Hooks:\n    OnConnect:\n    - exec sleep 60 \u0026\n# execute the `sleep 60` command in background (non-blocking)\n# if you quit your ssh connection, the process will continue in background.\n```\n\n##### Write driver\n\nWrite driver uses [Golang's template system](https://golang.org/pkg/text/template/) to write out data to stdout\n\nUsage: `write \u003cline:string...\u003e`\n\n```yaml\ndefaults:\n  Hooks:\n    OnConnect:\n    - write New SSH connection to {{.Host.Prototype}}.\n# writes: \"New SSH connection to moul@127.0.0.1:22.\" on the terminal on connection\n```\n\n```yaml\ndefaults:\n  Hooks:\n    OnDisconnect:\n    - \"write SSH connection to {{.Host.Name}} closed, {{ .Stats.WrittenBytes }} bytes written in {{ .Stats.ConnectionDuration }} ({{ .Stats.AverageSpeed }})\"\n# writes: SSH connection to localhost closed, 40 bytes written.\n```\n\n##### Notify driver\n\nNotify driver uses [Golang's template system](https://golang.org/pkg/text/template/) to open Desktop notifications.\n\n  * **Mac OS X**: Built-in support\n  * **Linux**: Depends on [gnotifier](https://github.com/haklop/gnotifier)\n  * **Windows**: Not supported\n  * **BSD**: Not supported\n\nUsage: `notify \u003cline:string...\u003e`\n\n```yaml\ndefaults:\n  Hooks:\n    OnConnect: notify New SSH connection to {{.Host.Prototype}}.\n```\n\n![](https://github.com/moul/assh/raw/master/resources/new_connection_notification.png)\n\n```yaml\ndefaults:\n  Hooks:\n    OnDisconnect:\n    - \"notify SSH connection to {{.Host.Name}} closed, {{ .Stats.WrittenBytes }} bytes written in {{ .Stats.ConnectionDuration }} ({{ .Stats.AverageSpeed }})\"\n```\n\n![](https://github.com/moul/assh/raw/master/resources/closed_connection_notification.png)\n\n## Configuration\n\n`assh` now manages the `~/.ssh/config` file, take care to keep a backup your `~/.ssh/config` file.\n\n`~/.ssh/assh.yml` is a [YAML](http://www.yaml.org/spec/1.2/spec.html) file containing:\n\n  * a `hosts` dictionary containing multiple *HOST* definitions\n  * a `defaults` section containing global flags\n  * and an `includes` section containing path to other configuration files\n\n```yaml\nhosts:\n\n  homer:\n    # ssh homer -\u003e  ssh 1.2.3.4 -p 2222 -u robert\n    Hostname: 1.2.3.4\n    User: robert\n    Port: 2222\n\n  bart:\n    # ssh bart -\u003e   ssh 5.6.7.8 -u bart           \u003c- direct access\n    #            or ssh 5.6.7.8/homer -u bart     \u003c- using homer as a gateway\n    Hostname: 5.6.7.8\n    User: bart\n    Gateways:\n    - direct                   # tries a direct access first\n    - homer                    # fallback on homer gateway\n\n  maggie:\n    # ssh maggie -\u003e   ssh 5.6.7.8 -u maggie       \u003c- direct access\n    #              or ssh 5.6.7.8/homer -u maggie   \u003c- using homer as a gateway\n    User: maggie\n    Inherits: bart             # inherits rules from \"bart\"\n\n  bart-access:\n    # ssh bart-access -\u003e  ssh home.simpson.springfield.us -u bart\n    Inherits:\n    - bart-template\n    - simpson-template\n\n  lisa-access:\n    # ssh lisa-access -\u003e  ssh home.simpson.springfield.us -u lisa\n    Inherits:\n    - lisa-template\n    - simpson-template\n\n  marvin:\n    # ssh marvin    -\u003e ssh marvin    -p 23\n    # ssh sad-robot -\u003e ssh sad-robot -p 23\n    # ssh bighead   -\u003e ssh bighead   -p 23\n    # aliases inherit everything from marvin, except hostname\n    Port: 23\n    Aliases:\n    - sad-robot\n    - bighead\n\n  dolphin:\n    # ssh dolphin   -\u003e ssh dolphin -p 24\n    # ssh ecco      -\u003e ssh dolphin -p 24\n    # same as above, but with fixed hostname\n    Port: 24\n    Hostname: dolphin\n    Aliases: ecco\n    RateLimit: 10M # 10Mbytes/second rate limiting\n\n  schooltemplate:\n    User: student\n    IdentityFile: ~/.ssh/school-rsa\n    ForwardX11: yes\n\n  schoolgw:\n    # ssh school -\u003e   ssh gw.school.com -l student -o ForwardX11=no -i ~/.ssh/school-rsa\n    Hostname: gw.school.com\n    ForwardX11: no\n    Inherits: schooltemplate\n\n  \"expanded-host[0-7]*\":\n    # ssh somehost2042 -\u003e       ssh somehost2042.some.zone\n    Hostname: \"%h.some.zone\"\n\n  vm-*.school.com:\n    # ssh vm-42.school.com -\u003e   ssh vm-42.school.com/gw.school.com -l student -o ForwardX11=yes -i ~/.ssh/school-rsa\n    Gateways: schoolgw\n    Inherits: schooltemplate\n    # do not automatically create `ControlPath` -\u003e may result in error\n    ControlMasterMkdir: true\n\n  \"*.shortcut1\":\n    ResolveCommand: /bin/sh -c \"echo %h | sed s/.shortcut1/.my-long-domain-name.com/\"\n\n  \"*.shortcut2\":\n    ResolveCommand: /bin/sh -c \"echo $(echo %h | sed s/.shortcut2//).my-other-long-domain-name.com\"\n\n  \"*.scw\":\n    # ssh toto.scw -\u003e 1. dynamically resolves the IP address\n    #                 2. ssh {resolved ip address} -u root -p 22 -o UserKnownHostsFile=null -o StrictHostKeyChecking=no\n    # requires github.com/scaleway/scaleway-cli\n    ResolveCommand: /bin/sh -c \"scw inspect -f {{.PublicAddress.IP}} server:$(echo %h | sed s/.scw//)\"\n    User: root\n    Port: 22\n    UserKnownHostsFile: /dev/null\n    StrictHostKeyChecking: no\n\n  my-env-host:\n    User: user-$USER\n    Hostname: ${HOSTNAME}${HOSTNAME_SUFFIX}\n\ntemplates:\n  # Templates are similar to Hosts; you can inherit from them\n  # but you cannot ssh to a template\n  bart-template:\n    User: bart\n  lisa-template:\n    User: lisa\n  simpson-template:\n    Host: home.simpson.springfield.us\n\ndefaults:\n  # Defaults are applied to each hosts\n  ControlMaster: auto\n  ControlPath: ~/tmp/.ssh/cm/%h-%p-%r.sock\n  ControlPersist: yes\n  Port: 22\n  User: bob\n  Hooks:\n    # Automatically backup ~/.ssh/config\n    BeforeConfigWrite:\n      - 'exec set -x; cp {{.SSHConfigPath}} {{.SSHConfigPath}}.bkp'\n\n    AfterConfigWrite:\n      # Concat another `ssh_config` file with the one just generated by `assh`\n      - 'exec cat ~/.ssh/my-heroku-generated-config \u003e\u003e {{.SSHConfigPath}}'\n\n      # Alert me with a Desktop notification\n      - notify \"{{.SSHConfigPath}} has been rewritten\"\n\n    OnConnect:\n      # Log internal information to a file\n      - exec printf '{{.}}' | jq . \u003e\u003e ~/.ssh/last_connected_host.txt\n\n      # Alert me with a Desktop notification\n      - notify New SSH connection to {{.Host.Prototype}} at {{.Stats.ConnectedAt}}\n\n      # Write the host prototype to the terminal stderr\n      - write New SSH connection to {{.Host.Prototype}}\n\n    OnDisconnect:\n      # write on terminal and in a Desktop notification some statistics about the finished connection\n      - \"write  SSH connection to {{.Host.HostName}} closed, {{.Stats.WrittenBytes }} bytes written in {{.Stats.ConnectionDuration}} ({{.Stats.AverageSpeed}}bps)\"\n      - \"notify SSH connection to {{.Host.HostName}} closed, {{.Stats.WrittenBytes }} bytes written in {{.Stats.ConnectionDuration}} ({{.Stats.AverageSpeed}}bps)\"\n\nincludes:\n- ~/.ssh/assh.d/*.yml\n- /etc/assh.yml\n- $ENV_VAR/blah-blah-*/*.yml\n\nASSHBinaryPath: ~/bin/assh  # optionally set the path of assh\n```\n\nFor further inspiration, these [`assh.yml` files on public GitHub projects](https://github.com/search?utf8=%E2%9C%93\u0026q=in%3Apath+assh.yml+extension%3Ayml\u0026type=Code) can educate you on how people are using assh\n\n## Usage\n\n`assh` usage\n\n```\nNAME:\n   assh - advanced ssh config\n\nUSAGE:\n   assh [global options] command [command options] [arguments...]\n\nVERSION:\n2.8.0 (HEAD)\n\nAUTHOR(S):\n   Manfred Touron \u003chttps://github.com/moul/assh\u003e\n\nCOMMANDS:\n   ping          Send packets to the SSH server and display statistics\n   info          Display system-wide information\n   config        Manage ssh and assh configuration\n   sockets       Manage control sockets\n   help, h       Shows a list of commands or help for one command\n\nGLOBAL OPTIONS:\n  --config value, -c value       Location of config file (default: \"~/.ssh/assh.yml\") [$ASSH_CONFIG]\n  --debug, -D                    Enable debug mode [$ASSH_DEBUG]\n  --verbose, -V                  Enable verbose mode\n  --help, -h                     show help\n  --version, -v                  print the version\n```\n\n### Usage examples\n\n#### `assh config build`\n\nRewrites and replaces the existing ~/.ssh/config file.\n\nThis action is automatically done by assh when detecting configuration changes.\nRunning this command is useful to set up assh or repair the configuration file.\n\n```console\n$ assh config build \u003e ~/.ssh/config\n```\n\n#### `assh config list`\n\nList hosts and options.\n\n```console\n$ assh config list\nListing entries\n\n    *.scw -\u003e root@[hostname_not_specified]:22\n        StrictHostKeyChecking=no [custom options]\n        UserKnownHostsFile=/dev/null [custom options]\n\n    *.shortcut1 -\u003e bob@[hostname_not_specified]:22\n\n    *.shortcut2 -\u003e bob@[hostname_not_specified]:22\n\n    bart -\u003e bart@5.6.7.8:22\n\n    bart-access -\u003e bob@[hostname_not_specified]:22\n\n    dolphin -\u003e bob@dolphin:24\n\n    expanded-host[0-7]* -\u003e bob@%h.some.zone:22\n\n    homer -\u003e robert@1.2.3.4:2222\n\n    lisa-access -\u003e bob@[hostname_not_specified]:22\n\n    maggie -\u003e maggie@[hostname_not_specified]:22\n\n    marvin -\u003e bob@[hostname_not_specified]:23\n\n    my-env-host -\u003e user-moul@[hostname_not_specified]:22\n\n    schoolgw -\u003e bob@gw.school.com:22\n        ForwardX11=no [custom options]\n\n    schooltemplate -\u003e student@[hostname_not_specified]:22\n        ForwardX11=yes [custom options]\n        IdentityFile=~/.ssh/school-rsa [custom options]\n\n    vm-*.school.com -\u003e bob@[hostname_not_specified]:22\n\n    (*) General options:\n        ControlMaster: auto\n        ControlPath: ~/tmp/.ssh/cm/%h-%p-%r.sock\n        ControlPersist: yes\n        Port: 22\n        User: bob\n```\n\n#### `assh config graphviz`\n\nGenerate a [graphviz](http://www.graphviz.org/) graph of the hosts\n\n```console\n$ assh config graphviz | dot -Tpng \u003e assh-hosts.png\n```\n\n![](https://github.com/moul/assh/raw/master/resources/graphviz.png)\n\n#### `assh config search \u003ckeyword\u003e`\n\nSearch for `\u003ckeyword\u003e` in hosts and host options.\n\n```console\n$ assh config search bart\nListing results for bart:\n    bart -\u003e bart@5.6.7.8:22\n    bart-access -\u003e moul@[hostname_not_specified]:22\n```\n\n#### `assh info`\n\nDisplay system-wide information.\n\n```console\n$ assh info\nDebug mode (client): false\nCLI Path: /path/to/assh\nGo version: go1.6.2\nOS/Arch: darwin/amd64\n\nRC files:\n- ~/.ssh/assh.yml\n- ~/.ssh/assh.d/hosts.yml\n- ~/.ssh/assh.d/moul.yml\n- ~/.ssh/assh.d/test.yml\n\nStatistics:\n- 299 hosts\n- 2 templates\n- 4 included files\n```\n\n#### `assh sockets list`\n\nList active control sockets.\n\n```console\n$ assh sockets list\n4 active control sockets in \"~/.ssh/cm/\":\n\n- bart/homer/lisa-22-root.sock (14 minutes)\n- bart/homer-22-root.sock (14 minutes)\n- bart-22-root.sock (14 minutes)\n- marge-22-bart.sock (1 hour)\n```\n\n#### `assh sockets flush`\n\nClose active control sockets.\n\n```console\n$ assh sockets flush\nClosed 4 control sockets.\n```\n\n#### `assh sockets master`\n\nCreate a master control sockets.\n\n```console\n$ assh sockets master\n```\n\n#### `assh ping`\n\nSend packets to the SSH server and display stats.\n\n```console\n$ assh ping -c 4 localhost\nPING localhost (127.0.0.1) PORT 22 (ssh) PROTO tcp\nConnected to 127.0.0.1: seq=0 time=321µs protocol=tcp port=22\nConnected to 127.0.0.1: seq=1 time=501µs protocol=tcp port=22\nConnected to 127.0.0.1: seq=2 time=550µs protocol=tcp port=22\nConnected to 127.0.0.1: seq=3 time=641µs protocol=tcp port=22\n\n--- localhost assh ping statistics ---\n4 packets transmitted, 4 packets received, 0.00% packet loss\nround-trip min/avg/max = 321µs/503.25µs/641µs\n```\n\n## Install\n\nGet the latest version using GO (recommended way):\n\n```bash\ngo install moul.io/assh/v2@latest\n```\n\n**note**: tested with Go1.7 or above\n\n---\n\nGet the latest released version using homebrew (Mac OS X):\n\n```bash\nbrew install assh\n```\n\nBuild the latest version\n\n```bash\nbrew install assh --HEAD\n```\n\n---\n\nGet a released version on: https://github.com/moul/assh/releases\n\n---\n\nInstall with [asdf-vm](https://asdf-vm.com/):\n```bash\nasdf plugin add assh\nasdf install assh latest\nasdf global assh latest\n```\n\n---\n\n### Register the wrapper (optional)\n\nTo improve experience when using advanced pattern matching, add the following at the end of your `.bashrc` / `.zshrc` / `config.fish`:\n\n```bash\nalias ssh=\"assh wrapper ssh --\"\n```\n\nThis step is not *mandatory* but highly *recommended*.\n\n---\n\n**Note**: `ssh` does not understand advanced patterns;\nTo bypass this limitation, `assh` maintains a list of *known hosts* and regenerate the `~/.ssh/config` with all those expanded *known hosts*.\n\nWithout the wrapper, the `~/.ssh/config` risks to be outdated when connecting to a new host for the first time and you will need to launch the command again.\n\nWith the wrapper, `ssh` will *always* be called with an updated `~/.ssh/config` file.\n\n## Getting started\n\n  1. Backup your old `~/.ssh/config`: `cp ~/.ssh/config ~/.ssh/config.backup`\n  2. Create a new `~/.ssh/assh.yml` file\n  3. Run `assh config build \u003e ~/.ssh/config` to validate the syntax of your `~/.ssh/assh.yml` file and automatically build your `~/.ssh/config` file\n  4. You are ready!\n\n## Webapp\n\n`assh` contains an experimental web application hosted on heroku: https://assh.herokuapp.com/\n\n---\n\nConvert an `assh.yml` file to `ssh_config` format:\n\n```console\n$ http --form POST https://assh-dev.herokuapp.com/assh-to-ssh assh_config=@~/.ssh/assh.d/test.yml | jq -r .ssh_config\n# This file was automatically generated by assh v2.8.0\n# on 2018-07-03 21:06:56 +0000 UTC, based on ~/.ssh/assh.yml\n#\n# more info: https://github.com/moul/assh\n\n# host-based configuration\nHost *.scw\n  Port 22\n  StrictHostKeyChecking no\n  User root\n  UserKnownHostsFile /dev/null\n  # ResolveCommand: /bin/sh -c \"scw inspect -f {{.PublicAddress.IP}} server:$(echo %h | sed s/.scw//)\"\n\nHost lalala\n  Port 22\n  User moul\n  # HostName: 127.0.0.1\n\nHost toto[0-5]toto\n  User samantha\n\n# global configuration\nHost *\n  ProxyCommand assh connect --port=%p %h\n```\n\n---\n\n* [Apiary Documentation](http://docs.assh.apiary.io/)\n\n\n## Docker\n\nExperimental: `assh` may run in Docker, however you will have limitations:\n\n  * The `assh` containers does not have any binaries except `assh`, you can't use `ProxyCommand`, `ResolveCommand`...\n  * Docker may run on another host, `ssh localhost` will ssh to Docker host\n\n```console\ndocker run -it --rm -v ~/.ssh:/.ssh moul/assh --help\n```\n\n`assh` in Docker is slower and has more limitations, but it may be useful for testing or if you plan to use a Docker host as a remote Gateway\n\n## Alternative version\n\n  * [v1](https://github.com/moul/assh/tree/v1) (2009-2015) - The original implementation. It worked quite well, but was a lot slower, less portable, harder to install for the user and harder to work on to develop new features and fix bugs\n\n## Troubleshooting\n\n### I can't use gateways\n\n`assh` uses the [built-in netcat mode of OpenSSH (shipped with OpenSSH 5.4)](https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Proxies_and_Jump_Hosts#Passing_through_a_gateway_using_netcat_mode) by default.\nIf your ssh client doesn't support this feature, you can configure a custom `ProxyCommand` configuration, i.e.,\n\n```yaml\nhosts:\n  myserver:\n    host: 1.2.3.4\n    gateways: mygateway\n    # configure a custom proxycommand\n    proxycommand: /bin/nc %h %p\n\n  mygateway:\n    host: 5.6.7.8\n```\n\n---\n\nYou can configure this rule globally:\n\n```yaml\ndefaults:\n  proxycommand: nc %h %p\n```\n\n---\n\nAlso, be sure to have netcat installed on your system, or use an alternative proxy binary, i.e., `socat`.\n\n### How to Configure resolver to parse `/etc/hosts` and/or handle **mDNS** requests\n\n**assh** resolves hostnames using the system built-in resolver, depending on the OS, you can enable new features and/or change modules order.\n\n  * [Linux - nsswitch documentation](http://man7.org/linux/man-pages/man5/nsswitch.conf.5.html)\n  * [Linux - mDNS support (nss-mdns)](http://0pointer.de/lennart/projects/nss-mdns/)\n  * [Mac OS X - `/etc/resolv.conf` documentation](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man5/resolver.5.html)\n\n### `unix_listener: \"/Users/.../.ssh/cm/...\" too long for Unix domain socket`\n\nStarting with `OpenSSH v6.7` the socket name can be shortened by configuring `%C` for the name expansion.\n\n```yaml\ndefaults:\n  ControlPath: ~/tmp/.ssh/cm/%C.sock\n```\n\n`%C` is a unique identifier based on a hash of the tuple of (local host, remote user, hostname, port).\n\n### How to disable the automatic configuration rewrite\n\nEach time you call `ssh`, `assh` will check if the generated `~/.ssh/config` file is outdated.\n\nBy default, it will transparently regenerate the configuration file if needed.\n\nYou can disable this behavior by generating the configuration file like this:\n\n```bash\nassh config build --no-automatic-rewrite\n```\n\n## 3rd Party Integration\n\n### Ansible\n\nIn your ansible.cfg under ssh_connection, make sure you have the following, changing the path to your assh:\n```\n[ssh_connection]\nansible_ssh_executable = '/usr/local/bin/assh wrapper ssh'\n```\n\n### 3rd Party Projects\n\n  * [ansible-dotfiles-assh](https://github.com/wrboyce/ansible-dotfiles-assh): Ansible - Configure SSH with   ASSH\n  * [appflow](https://github.com/ttssdev/appflow): Multitenant environment automation\n\n## Contributors\n\n### Code Contributors\n\nThis project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].\n\u003ca href=\"https://github.com/moul/assh/graphs/contributors\"\u003e\u003cimg src=\"https://opencollective.com/assh/contributors.svg?width=890\u0026button=false\" /\u003e\u003c/a\u003e\n\n### Financial Contributors\n\nBecome a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/assh/contribute)]\n\n#### Individuals\n\n\u003ca href=\"https://opencollective.com/assh\"\u003e\u003cimg src=\"https://opencollective.com/assh/individuals.svg?width=890\"\u003e\u003c/a\u003e\n\n#### Organizations\n\nSupport this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/assh/contribute)]\n\n\u003ca href=\"https://opencollective.com/assh/organization/0/website\"\u003e\u003cimg src=\"https://opencollective.com/assh/organization/0/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/assh/organization/1/website\"\u003e\u003cimg src=\"https://opencollective.com/assh/organization/1/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/assh/organization/2/website\"\u003e\u003cimg src=\"https://opencollective.com/assh/organization/2/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/assh/organization/3/website\"\u003e\u003cimg src=\"https://opencollective.com/assh/organization/3/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/assh/organization/4/website\"\u003e\u003cimg src=\"https://opencollective.com/assh/organization/4/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/assh/organization/5/website\"\u003e\u003cimg src=\"https://opencollective.com/assh/organization/5/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/assh/organization/6/website\"\u003e\u003cimg src=\"https://opencollective.com/assh/organization/6/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/assh/organization/7/website\"\u003e\u003cimg src=\"https://opencollective.com/assh/organization/7/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/assh/organization/8/website\"\u003e\u003cimg src=\"https://opencollective.com/assh/organization/8/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/assh/organization/9/website\"\u003e\u003cimg src=\"https://opencollective.com/assh/organization/9/avatar.svg\"\u003e\u003c/a\u003e\n\n\n### Stargazers over time\n\n[![Stargazers over time](https://starchart.cc/moul/assh.svg)](https://starchart.cc/moul/assh)\n      \n\n## License\n\n© 2009-2021 Manfred Touron - MIT License\n","funding_links":["https://github.com/sponsors/moul","https://patreon.com/moul","https://opencollective.com/moul","https://manfred.life/donate","https://opencollective.com/assh","https://opencollective.com/assh/contribute","https://opencollective.com/assh/organization/0/website","https://opencollective.com/assh/organization/1/website","https://opencollective.com/assh/organization/2/website","https://opencollective.com/assh/organization/3/website","https://opencollective.com/assh/organization/4/website","https://opencollective.com/assh/organization/5/website","https://opencollective.com/assh/organization/6/website","https://opencollective.com/assh/organization/7/website","https://opencollective.com/assh/organization/8/website","https://opencollective.com/assh/organization/9/website"],"categories":["Go","开源类库","SSH","Apps","Open source library","Go (531)","automation"],"sub_categories":["终端工具","Packages","`.ssh/config`","Terminal Tools"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoul%2Fassh","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmoul%2Fassh","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoul%2Fassh/lists"}