feat: docs site (#286)

* feat: docs site

* docs: copy

* chore(docs): update cli post

* revert

* chore: go.mod
This commit is contained in:
Eric Bower
2024-01-29 10:17:13 -05:00
committed by GitHub
parent 689211287c
commit 0c4f193f7d
33 changed files with 3738 additions and 424 deletions

27
.github/workflows/docs.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: docs
on:
push:
branches:
- main
jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set outputs
id: vars
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- uses: actions/setup-go@v4
with:
go-version: '1.21'
- name: build docs site
run: make ssg
- name: publish to pgs
uses: picosh/pgs-action@v3
with:
user: hey
key: ${{ secrets.PRIVATE_KEY }}
src: './public/'
project: "sish-${{ steps.vars.outputs.sha_short }}"
promote: "sish-prod"
retain: "sish-"

2
.gitignore vendored
View File

@@ -2,3 +2,5 @@ deploy/
dist/
sish
__debug_bin
docs/public/*
!docs/public/.gitkeep

21
Makefile Normal file
View File

@@ -0,0 +1,21 @@
clean:
rm -rf ./docs/public/*
echo "" > ./docs/public/.gitkeep
.PHONY: clean
ssg:
go run ./docs/cmd
cp ./docs/static/* ./docs/public
.PHONY: ssg
docs: ssg
rsync -vr ./docs/public/ hey@pgs.sh:/sish-local
.PHONY: docs
docs-prod: ssg
rsync -vr ./docs/public/ hey@pgs.sh:/sish-prod
.PHONY: docs-prod
dev:
go run main.go --http-address localhost:3000 --domain testing.ssi.sh
.PHONY: dev

418
README.md
View File

@@ -2,425 +2,35 @@
An open source serveo/ngrok alternative.
## Deploy
[Read the docs.](https://docs.ssi.sh)
Builds are made automatically for each commit to the repo and are pushed to Dockerhub. Builds are tagged using a commit sha,
branch name, tag, latest if released on main. You can find a list [here](https://hub.docker.com/r/antoniomika/sish/tags).
Each release builds separate `sish` binaries that can be downloaded from [here](https://github.com/antoniomika/sish/releases) for various OS/archs. Feel free to either use the automated binaries or to build your own. If you submit a PR, images are
not built by default and will require a retag from a maintainer to be built.
## dev
1. Pull the Docker image
- `docker pull antoniomika/sish:latest`
2. Run the image
- ```bash
docker run -itd --name sish \
-v ~/sish/ssl:/ssl \
-v ~/sish/keys:/keys \
-v ~/sish/pubkeys:/pubkeys \
--net=host antoniomika/sish:latest \
--ssh-address=:22 \
--http-address=:80 \
--https-address=:443 \
--https=true \
--https-certificate-directory=/ssl \
--authentication-keys-directory=/pubkeys \
--private-keys-directory=/keys \
--bind-random-ports=false
```
3. SSH to your host to communicate with sish
- `ssh -p 2222 -R 80:localhost:8080 ssi.sh`
## Docker Compose
You can also use Docker Compose to setup your sish instance. This includes taking
care of SSL via Let's Encrypt for you. This uses the
[adferrand/dnsrobocert](https://github.com/adferrand/dnsrobocert) container to handle issuing wildcard
certifications over DNS. For more information on how to use this, head to that link above. Generally, you
can deploy your service like so:
Clone the `sish` repo:
```bash
docker-compose -f deploy/docker-compose.yml up -d
git clone git@github.com:antoniomika/sish.git
cd sish
```
The domain and DNS auth info in `deploy/docker-compose.yml` and `deploy/le-config.yml` should be updated
to reflect your needs. You will also need to create a symlink that points to your domain's
Let's Encrypt certificates like:
Add your SSH public key:
```bash
ln -s /etc/letsencrypt/live/<your domain>/fullchain.pem deploy/ssl/<your domain>.crt
ln -s /etc/letsencrypt/live/<your domain>/privkey.pem deploy/ssl/<your domain>.key
cp ~/.ssh/id_ed25519.pub ./deploy/pubkeys
```
Careful: the symlinks need to point to `/etc/letsencrypt`, not a relative path. The symlinks will
not resolve on the host filesystem, but they will resolve inside of the sish container because it mounts
the letsencrypt files in /etc/letsencrypt, _not_ ./letsencrypt.
I use these files in my deployment of `ssi.sh` and have included them here for consistency.
## Google Cloud Platform
There is a tutorial for creating an instance in Google Cloud Platform
with sish fully setup that can be found [here](https://github.com/antoniomika/sish/blob/main/deploy/gcloud.md).
It can be accessed through [Google Cloud Shell](https://cloud.google.com/shell).
[![Open in Cloud Shell](https://gstatic.com/cloudssh/images/open-btn.svg)](https://ssh.cloud.google.com/cloudshell/editor?shellonly=true&cloudshell_git_repo=https%3A%2F%2Fgithub.com%2Fantoniomika%2Fsish&cloudshell_git_branch=main&cloudshell_tutorial=deploy%2Fgcloud.md)
## How it works
SSH can normally forward local and remote ports. This service implements
an SSH server that only handles forwarding and nothing else. The service supports
multiplexing connections over HTTP/HTTPS with WebSocket support. Just assign a
remote port as port `80` to proxy HTTP traffic and `443` to proxy HTTPS traffic.
If you use any other remote port, the server will listen to the port for TCP connections,
but only if that port is available.
You can choose your own subdomain instead of relying on a randomly assigned one
by setting the `--bind-random-subdomains` option to `false` and then selecting a
subdomain by prepending it to the remote port specifier:
`ssh -p 2222 -R foo:80:localhost:8080 ssi.sh`
If the selected subdomain is not taken, it will be assigned to your connection.
## Supported forwarding types
### HTTP forwarding
sish can forward any number of HTTP connections through SSH. It also provides logging the connections
to the connected client that has forwarded the connection and a web interface to see full request and
responses made to each forwarded connection. Each webinterface can be unique to the forwarded connection or
use a unified access token. To make use of HTTP forwarding, ports `[80, 443]` are used to tell sish that a
HTTP connection is being forwarded and that HTTP virtualhosting should be defined for the service. For
example, let's say I'm
developing a HTTP webservice on my laptop at port `8080` that uses websockets and I want to show one of my
coworkers who is not near me. I can forward the connection like so:
Run the binary:
```bash
ssh -R hereiam:80:localhost:8080 ssi.sh
go run main.go --http-address localhost:3000 --domain testing.ssi.sh
```
And then share the link `https://hereiam.ssi.sh` with my coworker. They should be able to access the service
seamlessly over HTTPS, with full websocket support working fine. Let's say `hereiam.ssi.sh` isn't available,
then sish will generate a random subdomain and give that to me.
We have an alias `make dev` for running the binary.
### TCP forwarding
Any TCP based service can be used with sish for TCP and alias forwarding. TCP forwarding
will establish a remote port on the server that you deploy sish to and will forward all connections
to that port through the SSH connection and to your local device. For example, if I was to run
a SSH server on my laptop with port `22` and want to be able to access it from anywhere at `ssi.sh:2222`,
I can use an SSH command on my laptop like so to forward the connection:
SSH to your host to communicate with sish:
```bash
ssh -R 2222:localhost:22 ssi.sh
```
I can use the forwarded connection to then access my laptop from anywhere:
```bash
ssh -p 2222 ssi.sh
```
### SNI forwarding
Sometimes, you may have multiple TCP services running on the same port.
If these services support [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication), you can have sish
route TLS connections to different backends based on the SNI name provided. For example, I have two webservices
(servers) and I want to offload TLS to each without sish offloading SSL. This can be achieved by disabling sish's
internal HTTPS service (you won't be able to use the service console for this however). Then, I can start a ssh
connection from each server like so:
From server A
```bash
ssh -R servera.example.com:443:localhost:443 ssi.sh sni-proxy=true
```
From server B
```bash
ssh -R serverb.example.com:443:localhost:443 ssi.sh sni-proxy=true
```
As long as server{a,b}.example.com points to where sish is hosted and a user can bind those hosts, TLS connections to
servera.example.com:443 will be forwarded to server A and TLS connections to serverb.example.com:443 will
be forwarded to server B. It is then up to each server to complete the TLS handshake and the subsequent request.
### TCP alias forwarding
Let's say instead I don't want the service to be accessible by the rest of the world, you can then use a TCP
alias. A TCP alias is a type of forwarded TCP connection that only exists inside of sish. You can gain access
to the alias by using SSH with the `-W` flag, which will forwarding the SSH process' stdin/stdout to the
fowarded TCP connection. In combination with authentication, this will guarantee your remote service is safe
from the rest of the world because you need to login to sish before you can access it. Changing the example
above for this would mean running the following command on my laptop:
```bash
ssh -R mylaptop:22:localhost:22 ssi.sh
```
sish won't publish port 22 or 2222 to the rest of the world anymore, instead it'll retain a pointer saying
that TCP connections made from within SSH after a user has authenticated to `mylaptop:22` should be
forwarded to the forwarded TCP tunnel. Then I can use the forwarded connection access my laptop from
anywhere using:
```bash
ssh -o ProxyCommand="ssh -W %h:%p ssi.sh" mylaptop
```
Shorthand for which is this with newer SSH versions:
```bash
ssh -J ssi.sh mylaptop
```
You can also use TCP aliases with any port you would like. If for example you wanted to use an alias
with port `80` or `443` (default to a HTTP tunnel), provide the command `tcp-alias=true` to the ssh command:
```bash
ssh -R service:80:localhost:80 ssi.sh tcp-alias=true
```
Aliases can be accessed on a different computer using SSH local forwards also. For the above, I could use:
```bash
ssh -L 80:service:80 ssi.sh
```
to then access the forwarded server service at `localhost:80` on the client side of the computer I am on.
## Authentication
If you want to use this service privately, it supports both public key and password
authentication. To enable authentication, set `--authentication=true` as one of your CLI
options and be sure to configure `--authentication-password` or `--authentication-keys-directory` to your
liking. The directory provided by `--authentication-keys-directory` is watched for changes and will reload
the authorized keys automatically. The authorized cert index is regenerated on directory
modification, so removed public keys will also automatically be removed. Files in this
directory can either be single key per file, or multiple keys per file separated by newlines,
similar to `authorized_keys`. Password auth can be disabled by setting `--authentication-password=""` as a
CLI option.
One of my favorite ways of using this for authentication is like so:
```bash
sish@sish0:~/sish/pubkeys# curl https://github.com/antoniomika.keys > antoniomika
```
This will load my public keys from GitHub, place them in the directory that sish is watching,
and then load the pubkey. As soon as this command is run, I can SSH normally and it will authorize me.
## Custom domains
sish supports allowing users to bring custom domains to the service, but SSH key auth is required to be
enabled. To use this feature, you must setup TXT and CNAME/A records for the domain/subdomain you would
like to use for your forwarded connection. The CNAME/A record must point to the domain or IP that is hosting
sish. The TXT record must be be a `key=val` string that looks like:
```text
sish=SSHKEYFINGERPRINT
```
Where `SSHKEYFINGERPRINT` is the fingerprint of the key used for logging into the server. You can set
multiple TXT records and sish will check all of them to ensure at least one is a match. You can retrieve
your key fingerprint by running:
```bash
ssh-keygen -lf ~/.ssh/id_rsa | awk '{print $2}'
```
If you trust the users connecting to sish and would like to allow any domain to be used with sish
(bypassing verification), there are a few added flags to aid in this. This is especially useful when
adding multiple wildcard certificates to sish in order to not need to automatically provision Let's
Encrypt certs. To disable verfication, set `--bind-any-host=true`, which will allow and subdomain/domain
combination to be used. To only allow subdomains of a certain subset of domains, you can set `--bind-hosts`
to a comma separated list of domains that are allowed to be bound.
To add certficates for sish to use, configure the `--https-certificate-directory` flag to point to a dir
that is accessible by sish. In the directory, sish will look for a combination of files that look like
`name.crt` and `name.key`. `name` can be arbitrary in either case, it just needs to be unique to the cert
and key pair to allow them to be loaded into sish.
## Load balancing
sish can load balance any type of forwarded connection, but this needs to be enabled when starting sish
using the `--http-load-balancer`,
`--tcp-load-balancer`, and `--alias-load-balancer` flags. Let's say you have a few edge nodes
(raspberry pis) that are running a service internally but you want to be able to balance load across these
devices from the outside world. By enabling load balancing in sish, this happens automatically when a
device with the same forwarded TCP port, alias, or HTTP subdomain connects to sish. Connections will then be
evenly distributed to whatever nodes are connected to sish that match the forwarded connection.
## Whitelisting IPs
Whitelisting IP ranges or countries is also possible. Whole CIDR ranges can be
specified with the `--whitelisted-ips` option that accepts a comma-separated
string like "192.30.252.0/22,185.199.108.0/22". If you want to whitelist a single
IP, use the `/32` range.
To whitelist countries, use `--whitelisted-countries` with a comma-separated
string of countries in ISO format (for example, "pt" for Portugal). You'll also
need to set `--geodb` to `true`.
## DNS Setup
To use sish, you need to add a wildcard DNS record that is used for multiplexed subdomains.
Adding an `A` record with `*` as the subdomain to the IP address of your server is the simplest way to achieve this configuration.
## Notes
1. This is by no means production ready in any way. This was hacked together and solves a fairly specific
use case.
- You can help it get production ready by submitting PRs/reviewing code/writing tests/etc
2. This is a fairly simple implementation, I've intentionally cut corners in some places to make it easier
to write.
3. If you have any questions or comments, feel free to reach out via email
[me@antoniomika.me](mailto:me@antoniomika.me)
or on [freenode IRC #sish](https://kiwiirc.com/client/chat.freenode.net:6697/#sish)
## Upgrading to v2.0
v2 introduces only a few breaking changes, namely around authentication. v2 enables authentication by default. If you were
an authenticated instance before, be sure to set `--authentication` accordingly. v2 also brings support for multiple
SSH host private keys, which allows you to use different encryption schemes. This changed the `--private-key-location` to
`--private-keys-directory`. Keys generated or previously used in sish will work as normal, just be sure to update this
argument if it was changed from the default.
## Upgrading to v1.0
There are numerous breaking changes in sish between pre-1.0 and post-1.0 versions. The largest changes are
found in the mapping of command flags and configuration params. Those have changed drastically, but it should be easy
to find the new counterpart. The other change is SSH keys that are supported for host key auth. sish
continues to support most modern keys, but by default if a host key is not found, it will create an OpenSSH
ED25519 key to use. Previous versions of sish would aes encrypt the pem block of this private key, but we
have since moved to using the native
[OpenSSH private key format](https://github.com/openssh/openssh-portable/blob/master/sshkey.c) to allow for
easy interop between OpenSSH tools. For this reason, you will either have to manually convert an AES
encrypted key or generate a new one.
## CLI Flags
```text
sish is a command line utility that implements an SSH server that can handle HTTP(S)/WS(S)/TCP multiplexing, forwarding and load balancing.
It can handle multiple vhosting and reverse tunneling endpoints for a large number of clients.
Usage:
sish [flags]
Flags:
--admin-console Enable the admin console accessible at http(s)://domain/_sish/console?x-authorization=admin-console-token
-j, --admin-console-token string The token to use for admin console access if it's enabled
--alias-load-balancer Enable the alias load balancer (multiple clients can bind the same alias)
--append-user-to-subdomain Append the SSH user to the subdomain. This is useful in multitenant environments
--append-user-to-subdomain-separator string The token to use for separating username and subdomain selection in a virtualhost (default "-")
--authentication Require authentication for the SSH service (default true)
--authentication-key-request-timeout duration Duration to wait for a response from the authentication key request (default 5s)
--authentication-key-request-url string A url to validate public keys for public key authentication.
sish will make an HTTP POST request to this URL with a JSON body containing an
OpenSSH 'authorized key' formatted public key, username,
and ip address. E.g.:
{"auth_key": string, "user": string, "remote_addr": string}
A response with status code 200 indicates approval of the auth key
-k, --authentication-keys-directory string Directory where public keys for public key authentication are stored.
sish will watch this directory and automatically load new keys and remove keys
from the authentication list (default "deploy/pubkeys/")
--authentication-keys-directory-watch-interval duration The interval to poll for filesystem changes for SSH keys (default 200ms)
-u, --authentication-password string Password to use for SSH server password authentication
--banned-aliases string A comma separated list of banned aliases that users are unable to bind
-o, --banned-countries string A comma separated list of banned countries. Applies to HTTP, TCP, and SSH connections
-x, --banned-ips string A comma separated list of banned ips that are unable to access the service. Applies to HTTP, TCP, and SSH connections
-b, --banned-subdomains string A comma separated list of banned subdomains that users are unable to bind (default "localhost")
--bind-any-host Allow binding any host when accepting an HTTP listener
--bind-hosts string A comma separated list of other hosts a user can bind. Requested hosts should be subdomains of a host in this list
--bind-http-auth Allow binding http auth on a forwarded host (default true)
--bind-http-path Allow binding specific paths on a forwarded host (default true)
--bind-random-aliases Force bound alias tunnels to use random aliases instead of user provided ones (default true)
--bind-random-aliases-length int The length of the random alias to generate if a alias is unavailable or if random aliases are enforced (default 3)
--bind-random-ports Force TCP tunnels to bind a random port, where the kernel will randomly assign it (default true)
--bind-random-subdomains Force bound HTTP tunnels to use random subdomains instead of user provided ones (default true)
--bind-random-subdomains-length int The length of the random subdomain to generate if a subdomain is unavailable or if random subdomains are enforced (default 3)
--bind-root-domain Allow binding the root domain when accepting an HTTP listener
--bind-wildcards Allow binding wildcards when accepting an HTTP listener
--cleanup-unauthed Cleanup unauthed SSH connections after a set timeout (default true)
--cleanup-unauthed-timeout duration Duration to wait before cleaning up an unauthed connection (default 5s)
--cleanup-unbound Cleanup unbound (unforwarded) SSH connections after a set timeout
--cleanup-unbound-timeout duration Duration to wait before cleaning up an unbound (unforwarded) connection (default 5s)
-c, --config string Config file (default "config.yml")
--debug Enable debugging information
--debug-interval duration Duration to wait between each debug loop output if debug is true (default 2s)
-d, --domain string The root domain for HTTP(S) multiplexing that will be appended to subdomains (default "ssi.sh")
--force-all-https Redirect all requests to the https server
--force-https Allow indiviual binds to request for https to be enforced
--force-requested-aliases Force the aliases used to be the one that is requested. Will fail the bind if it exists already
--force-requested-ports Force the ports used to be the one that is requested. Will fail the bind if it exists already
--force-requested-subdomains Force the subdomains used to be the one that is requested. Will fail the bind if it exists already
--force-tcp-address Force the address used for the TCP interface to be the one defined by --tcp-address
--geodb Use a geodb to verify country IP address association for IP filtering
-h, --help help for sish
-i, --http-address string The address to listen for HTTP connections (default "localhost:80")
--http-load-balancer Enable the HTTP load balancer (multiple clients can bind the same domain)
--http-port-override int The port to use for http command output. This does not affect ports used for connecting, it's for cosmetic use only
--http-request-port-override int The port to use for http requests. Will default to 80, then http-port-override. Otherwise will use this value
--https Listen for HTTPS connections. Requires a correct --https-certificate-directory
-t, --https-address string The address to listen for HTTPS connections (default "localhost:443")
-s, --https-certificate-directory string The directory containing HTTPS certificate files (name.crt and name.key). There can be many crt/key pairs (default "deploy/ssl/")
--https-certificate-directory-watch-interval duration The interval to poll for filesystem changes for HTTPS certificates (default 200ms)
--https-ondemand-certificate Enable retrieving certificates on demand via Let's Encrypt
--https-ondemand-certificate-accept-terms Accept the Let's Encrypt terms
--https-ondemand-certificate-email string The email to use with Let's Encrypt for cert notifications. Can be left blank
--https-port-override int The port to use for https command output. This does not affect ports used for connecting, it's for cosmetic use only
--https-request-port-override int The port to use for https requests. Will default to 443, then https-port-override. Otherwise will use this value
--idle-connection Enable connection idle timeouts for reads and writes (default true)
--idle-connection-timeout duration Duration to wait for activity before closing a connection for all reads and writes (default 5s)
--load-templates Load HTML templates. This is required for admin/service consoles (default true)
--load-templates-directory string The directory and glob parameter for templates that should be loaded (default "templates/*")
--localhost-as-all Enable forcing localhost to mean all interfaces for tcp listeners (default true)
--log-to-client Enable logging HTTP and TCP requests to the client
--log-to-file Enable writing log output to file, specified by log-to-file-path
--log-to-file-compress Enable compressing log output files
--log-to-file-max-age int The maxium number of days to store log output in a file (default 28)
--log-to-file-max-backups int The maxium number of rotated logs files to keep (default 3)
--log-to-file-max-size int The maximum size of outputed log files in megabytes (default 500)
--log-to-file-path string The file to write log output to (default "/tmp/sish.log")
--log-to-stdout Enable writing log output to stdout (default true)
--ping-client Send ping requests to the underlying SSH client.
This is useful to ensure that SSH connections are kept open or close cleanly (default true)
--ping-client-interval duration Duration representing an interval to ping a client to ensure it is up (default 5s)
--ping-client-timeout duration Duration to wait for activity before closing a connection after sending a ping to a client (default 5s)
-n, --port-bind-range string Ports or port ranges that sish will allow to be bound when a user attempts to use TCP forwarding (default "0,1024-65535")
-p, --private-key-passphrase string Passphrase to use to encrypt the server private key (default "S3Cr3tP4$$phrAsE")
-l, --private-keys-directory string The location of other SSH server private keys. sish will add these as valid auth methods for SSH. Note, these need to be unencrypted OR use the private-key-passphrase (default "deploy/keys")
--proxy-protocol Use the proxy-protocol while proxying connections in order to pass-on IP address and port information
--proxy-protocol-listener Use the proxy-protocol to resolve ip addresses from user connections
--proxy-protocol-policy string What to do with the proxy protocol header. Can be use, ignore, reject, or require (default "use")
--proxy-protocol-timeout duration The duration to wait for the proxy proto header (default 200ms)
--proxy-protocol-use-timeout Use a timeout for the proxy-protocol read
-q, --proxy-protocol-version string What version of the proxy protocol to use. Can either be 1, 2, or userdefined.
If userdefined, the user needs to add a command to SSH called proxyproto=version (ie proxyproto=1) (default "1")
--redirect-root Redirect the root domain to the location defined in --redirect-root-location (default true)
-r, --redirect-root-location string The location to redirect requests to the root domain
to instead of responding with a 404 (default "https://github.com/antoniomika/sish")
--rewrite-host-header Force rewrite the host header if the user provides host-header=host.com (default true)
--service-console Enable the service console for each service and send the info to connected clients
--service-console-max-content-length int The max content length before we stop reading the response body (default -1)
-m, --service-console-token string The token to use for service console access. Auto generated if empty for each connected tunnel
--sni-load-balancer Enable the SNI load balancer (multiple clients can bind the same SNI domain/port)
--sni-proxy Enable the use of SNI proxying
--sni-proxy-https Enable the use of SNI proxying on the HTTPS port
-a, --ssh-address string The address to listen for SSH connections (default "localhost:2222")
--strip-http-path Strip the http path from the forward (default true)
--tcp-address string The address to listen for TCP connections
--tcp-aliases Enable the use of TCP aliasing
--tcp-aliases-allowed-users any Enable setting allowed users to access tcp aliases.
Can provide tcp-aliases-allowed-users in the ssh command set to a comma separated list of ssh fingerprints that can access an alias.
Provide any for all.
--tcp-load-balancer Enable the TCP load balancer (multiple clients can bind the same port)
--time-format string The time format to use for both HTTP and general log messages (default "2006/01/02 - 15:04:05")
--verify-dns Verify DNS information for hosts and ensure it matches a connecting users sha256 key fingerprint (default true)
--verify-ssl Verify SSL certificates made on proxied HTTP connections (default true)
-v, --version version for sish
-y, --whitelisted-countries string A comma separated list of whitelisted countries. Applies to HTTP, TCP, and SSH connections
-w, --whitelisted-ips string A comma separated list of whitelisted ips. Applies to HTTP, TCP, and SSH connections
ssh -p 2222 -R 80:localhost:8080 testing.ssi.sh
```
> The `testing.ssi.sh` DNS record points to `localhost` so anyone can use it for
> development

View File

@@ -1,20 +1,23 @@
# sish installation
sish is an open source serveo/ngrok alternative that can be used to open a tunnel
to localhost that is accessible to the open internet using only SSH. sish implements
an SSH server that can handle multiplexing of HTTP(S), TCP, and TCP Aliasing
sish is an open source serveo/ngrok alternative that can be used to open a
tunnel to localhost that is accessible to the open internet using only SSH. sish
implements an SSH server that can handle multiplexing of HTTP(S), TCP, and TCP
Aliasing
([more about this can be found in the README](https://github.com/antoniomika/sish/blob/main/README.md))
This tutorial will teach you how to:
* Setup an instance in Google Cloud using the [free tier](https://cloud.google.com/free)
* Add and modify authentication for users
* Access sish from a remote computer
- Setup an instance in Google Cloud using the
[free tier](https://cloud.google.com/free)
- Add and modify authentication for users
- Access sish from a remote computer
## Project selection
You first need to select a project to host the resources created in this tutorial.
I'd suggest creating a new project at this time where your sish instance will live.
You first need to select a project to host the resources created in this
tutorial. I'd suggest creating a new project at this time where your sish
instance will live.
<walkthrough-project-setup></walkthrough-project-setup>
## Access Google Cloud Shell
@@ -23,14 +26,18 @@ I'd suggest creating a new project at this time where your sish instance will li
## Create the instance running the container
Here is a command to create the instance running the sish container. This will start the container
on a hardened [Container Optimized OS](https://cloud.google.com/container-optimized-os/docs) and start
the service. This is just a starting command that runs sish on port `2222`, `80`, and `443`. If you
accept the [Let's Encrypt TOS](https://letsencrypt.org/repository/), you can enable automatic SSL cert loading.
This command does *NOT* include authentication and it is up to you to properly tune these parameters based on
the documentation [here](https://github.com/antoniomika/sish#cli-flags). Make sure to update `YOURDOMAIN`
to the actual domain you own. You will also need to setup the DNS records as described below. Also feel free
to change the `--zone` used for these commands.
Here is a command to create the instance running the sish container. This will
start the container on a hardened
[Container Optimized OS](https://cloud.google.com/container-optimized-os/docs)
and start the service. This is just a starting command that runs sish on port
`2222`, `80`, and `443`. If you accept the
[Let's Encrypt TOS](https://letsencrypt.org/repository/), you can enable
automatic SSL cert loading. This command does _NOT_ include authentication and
it is up to you to properly tune these parameters based on the documentation
[here](https://github.com/antoniomika/sish#cli-flags). Make sure to update
`YOURDOMAIN` to the actual domain you own. You will also need to setup the DNS
records as described below. Also feel free to change the `--zone` used for these
commands.
```bash
gcloud compute instances create-with-container sish \
@@ -82,8 +89,8 @@ gcloud compute firewall-rules create allow-all-tcp-sish \
Get the external IP address of your machine and create two DNS records
* An `A` record for YOURDOMAIN pointing it to the output below
* An `A` record for *.YOURDOMAIN pointing it to the output below
- An `A` record for YOURDOMAIN pointing it to the output below
- An `A` record for *.YOURDOMAIN pointing it to the output below
```bash
gcloud compute instances describe sish \
@@ -91,8 +98,9 @@ gcloud compute instances describe sish \
--format='get(networkInterfaces[0].accessConfigs[0].natIP)'
```
To confirm that the DNS records were created appropriately, you can run:
`dig @1.1.1.1 abcxyz.YOURDOMAIN` and `dig @1.1.1.1 YOURDOMAIN`. Both should get an answer with `status: NOERROR`.
To confirm that the DNS records were created appropriately, you can run:\
`dig @1.1.1.1 abcxyz.YOURDOMAIN` and `dig @1.1.1.1 YOURDOMAIN`. Both should get
an answer with `status: NOERROR`.
## Using sish

94
docs/cmd/ssg.go Normal file
View File

@@ -0,0 +1,94 @@
package main
import (
"github.com/picosh/pdocs"
)
func main() {
pager := pdocs.Pager("./docs/posts")
sitemap := []*pdocs.Sitemap{
{Text: "Home", Href: "/", Page: pager("home.md")},
{Text: "Sitemap", Href: "/sitemap", Page: pager("sitemap.md")},
{
Text: "Getting Started",
Href: "/getting-started",
Page: pager("getting-started.md"),
Tag: "Help",
Children: []*pdocs.Sitemap{
{Text: "Managed"},
{Text: "DNS"},
{Text: "Docker Compose"},
{Text: "Docker"},
{Text: "Google Cloud Platform"},
{Text: "Authentication"},
},
},
{
Text: "How it Works",
Href: "/how-it-works",
Page: pager("how-it-works.md"),
Tag: "Help",
Children: []*pdocs.Sitemap{
{Text: "Port Forward"},
{Text: "Traditional VPN"},
{Text: "sish Public"},
{Text: "sish Private"},
{Text: "Additional Details"},
},
},
{
Text: "Forwarding Types",
Href: "/forwarding-types",
Page: pager("forwarding-types.md"),
Tag: "Help",
Children: []*pdocs.Sitemap{
{Text: "HTTP"},
{Text: "TCP"},
{Text: "TCP Alias"},
{Text: "SNI"},
},
},
{
Text: "Cheatsheet",
Href: "/cheatsheet",
Page: pager("cheatsheet.md"),
Tag: "Help",
Children: []*pdocs.Sitemap{
{Text: "Remote forward SSH tunnels"},
{Text: "Local forward SSH tunnels"},
{Text: "HTTPS public access"},
{Text: "HTTPS private access"},
{Text: "Websocket"},
{Text: "TCP public access"},
{Text: "TCP private access"},
},
},
{Text: "CLI", Href: "/cli", Page: pager("cli.md"), Tag: "CLI"},
{
Text: "Advanced",
Href: "/advanced",
Page: pager("advanced.md"),
Children: []*pdocs.Sitemap{
{Text: "Choose your own subdomain"},
{Text: "Websocket Support"},
{Text: "Allowlist IPs"},
{Text: "Custom Domains"},
{Text: "Load Balancing"},
},
Tag: "Help",
},
{Text: "FAQ", Href: "/faq", Page: pager("faq.md"), Tag: "Help"},
}
config := &pdocs.DocConfig{
Sitemap: sitemap,
Out: "./docs/public",
Tmpl: "./docs/tmpl",
PageTmpl: "post.page.tmpl",
}
err := config.GenSite()
if err != nil {
panic(err)
}
}

81
docs/posts/advanced.md Normal file
View File

@@ -0,0 +1,81 @@
---
title: Advanced
description: How to customize sish
keywords: [sish, advanced, custom, domains, load, balancing, allowlist, ip]
---
# Choose your own subdomain
You can choose your own subdomain instead of relying on a randomly assigned one
by setting the `--bind-random-subdomains` option to `false` and then selecting a
subdomain by prepending it to the remote port specifier:
`ssh -p 2222 -R foo:80:localhost:8080 tuns.sh`
If the selected subdomain is not taken, it will be assigned to your connection.
# Websocket Support
The service supports multiplexing connections over HTTP/HTTPS with WebSocket
support. Just assign a remote port as port `80` to proxy HTTP traffic and `443`
to proxy HTTPS traffic. If you use any other remote port, the server will listen
to the port for TCP connections, but only if that port is available.
# Allowlist IPs
Whitelisting IP ranges or countries is also possible. Whole CIDR ranges can be
specified with the `--whitelisted-ips` option that accepts a comma-separated
string like "192.30.252.0/22,185.199.108.0/22". If you want to whitelist a
single IP, use the `/32` range.
To whitelist countries, use `--whitelisted-countries` with a comma-separated
string of countries in ISO format (for example, "pt" for Portugal). You'll also
need to set `--geodb` to `true`.
# Custom domains
sish supports allowing users to bring custom domains to the service, but SSH key
auth is required to be enabled. To use this feature, you must setup TXT and
CNAME/A records for the domain/subdomain you would like to use for your
forwarded connection. The CNAME/A record must point to the domain or IP that is
hosting sish. The TXT record must be be a `key=val` string that looks like:
```text
sish=SSHKEYFINGERPRINT
```
Where `SSHKEYFINGERPRINT` is the fingerprint of the key used for logging into
the server. You can set multiple TXT records and sish will check all of them to
ensure at least one is a match. You can retrieve your key fingerprint by
running:
```bash
ssh-keygen -lf ~/.ssh/id_rsa | awk '{print $2}'
```
If you trust the users connecting to sish and would like to allow any domain to
be used with sish (bypassing verification), there are a few added flags to aid
in this. This is especially useful when adding multiple wildcard certificates to
sish in order to not need to automatically provision Let's Encrypt certs. To
disable verfication, set `--bind-any-host=true`, which will allow and
subdomain/domain combination to be used. To only allow subdomains of a certain
subset of domains, you can set `--bind-hosts` to a comma separated list of
domains that are allowed to be bound.
To add certficates for sish to use, configure the
`--https-certificate-directory` flag to point to a dir that is accessible by
sish. In the directory, sish will look for a combination of files that look like
`name.crt` and `name.key`. `name` can be arbitrary in either case, it just needs
to be unique to the cert and key pair to allow them to be loaded into sish.
# Load balancing
sish can load balance any type of forwarded connection, but this needs to be
enabled when starting sish using the `--http-load-balancer`,
`--tcp-load-balancer`, and `--alias-load-balancer` flags. Let's say you have a
few edge nodes (raspberry pis) that are running a service internally but you
want to be able to balance load across these devices from the outside world. By
enabling load balancing in sish, this happens automatically when a device with
the same forwarded TCP port, alias, or HTTP subdomain connects to sish.
Connections will then be evenly distributed to whatever nodes are connected to
sish that match the forwarded connection.

121
docs/posts/cheatsheet.md Normal file
View File

@@ -0,0 +1,121 @@
---
title: Cheatsheet
description: sish usage reference
keywords: [sish, reference, cheatsheet]
---
[More info about forwarding types](/forwarding-types)
# Remote forward SSH tunnels
Full example:
```bash
ssh -R subdomain:80:localhost:3000 tuns.sh
# |__|
# remote forward
ssh -R subdomain:80:localhost:3000 tuns.sh
# |_________|
# subdomain.tuns.sh
ssh -R subdomain:80:localhost:3000 tuns.sh
# |______________|
# local web server
```
Dropping the subdomain:
```bash
ssh -R 80:localhost:3000 tuns.sh
# |__|
# autogenerated.tuns.sh
# access local server over http (443 for https)
ssh -R 80:localhost:3000 tuns.sh
# |______________|
# local web server over http
```
# Local forward SSH tunnels
Given remote forward to `subdomain.tuns.sh:80`
```bash
ssh -L 3000:subdomain:80 tuns.sh
# |__|
# local forward
ssh -L 3000:subdomain:80 tuns.sh
# |____|
# access tunnel at localhost:3000
ssh -L 3000:subdomain:80 tuns.sh
# |____________|
# subdomain.tuns.sh:80
```
# HTTPS public access
[More info](/forwarding-types#http)
- Eric has a web server running on `localhost:3000`
- Eric wants to share with anyone
- Tony wants to access it
Eric sets up remote forward:
```bash
ssh -R 80:localhost:3000 tuns.sh
```
# HTTPS private access
- Eric has a web server running on `localhost:3000`
- Eric only wants to share with Tony
- Tony wants to access it
Tony provides Eric with pubkey fingerprint:
```bash
ssh-keygen -lf ~/.ssh/id_ed25519
256 SHA256:4vNGm4xvuVxYbaIE5JX1KgTgncaF3x3w2lk+JMLOfd8 your_email@example.com (ED25519)
```
Eric sets up remote forward using Tony's fingerprint:
```bash
ssh -R private:3000:localhost:3000 tuns.sh tcp-aliases-allowed-users=SHA256:4vNGm4xvuVxYbaIE5JX1KgTgncaF3x3w2lk+JMLOfd8
```
Tony sets up local forward:
```bash
ssh -L 3000:private:3000 tuns.sh
```
Tony can access site at `http://localhost:3000`
# Websocket
Same method as [HTTPS public access](/cheatsheet#https-public-access).
# TCP public access
Expose SSH to the world
```bash
ssh -R 2222:localhost:22 tuns.sh
```
I can use the forwarded connection to then access my laptop from anywhere:
```bash
ssh -p 2222 tuns.sh
```
# TCP private access
For example if you want to use `netcat` to send files between computers.
[Setup a TCP alias](/forwarding-types#tcp-alias)

130
docs/posts/cli.md Normal file
View File

@@ -0,0 +1,130 @@
---
title: CLI
description: How use sish's CLI
keywords: [sish, cli]
---
```text
```text
sish is a command line utility that implements an SSH server that can handle HTTP(S)/WS(S)/TCP multiplexing, forwarding and load balancing.
It can handle multiple vhosting and reverse tunneling endpoints for a large number of clients.
Usage:
sish [flags]
Flags:
--admin-console Enable the admin console accessible at http(s)://domain/_sish/console?x-authorization=admin-console-token
-j, --admin-console-token string The token to use for admin console access if it's enabled
--alias-load-balancer Enable the alias load balancer (multiple clients can bind the same alias)
--append-user-to-subdomain Append the SSH user to the subdomain. This is useful in multitenant environments
--append-user-to-subdomain-separator string The token to use for separating username and subdomain selection in a virtualhost (default "-")
--authentication Require authentication for the SSH service (default true)
--authentication-key-request-timeout duration Duration to wait for a response from the authentication key request (default 5s)
--authentication-key-request-url string A url to validate public keys for public key authentication.
sish will make an HTTP POST request to this URL with a JSON body containing an
OpenSSH 'authorized key' formatted public key, username,
and ip address. E.g.:
{"auth_key": string, "user": string, "remote_addr": string}
A response with status code 200 indicates approval of the auth key
-k, --authentication-keys-directory string Directory where public keys for public key authentication are stored.
sish will watch this directory and automatically load new keys and remove keys
from the authentication list (default "deploy/pubkeys/")
--authentication-keys-directory-watch-interval duration The interval to poll for filesystem changes for SSH keys (default 200ms)
-u, --authentication-password string Password to use for SSH server password authentication
--banned-aliases string A comma separated list of banned aliases that users are unable to bind
-o, --banned-countries string A comma separated list of banned countries. Applies to HTTP, TCP, and SSH connections
-x, --banned-ips string A comma separated list of banned ips that are unable to access the service. Applies to HTTP, TCP, and SSH connections
-b, --banned-subdomains string A comma separated list of banned subdomains that users are unable to bind (default "localhost")
--bind-any-host Allow binding any host when accepting an HTTP listener
--bind-hosts string A comma separated list of other hosts a user can bind. Requested hosts should be subdomains of a host in this list
--bind-http-auth Allow binding http auth on a forwarded host (default true)
--bind-http-path Allow binding specific paths on a forwarded host (default true)
--bind-random-aliases Force bound alias tunnels to use random aliases instead of user provided ones (default true)
--bind-random-aliases-length int The length of the random alias to generate if a alias is unavailable or if random aliases are enforced (default 3)
--bind-random-ports Force TCP tunnels to bind a random port, where the kernel will randomly assign it (default true)
--bind-random-subdomains Force bound HTTP tunnels to use random subdomains instead of user provided ones (default true)
--bind-random-subdomains-length int The length of the random subdomain to generate if a subdomain is unavailable or if random subdomains are enforced (default 3)
--bind-root-domain Allow binding the root domain when accepting an HTTP listener
--bind-wildcards Allow binding wildcards when accepting an HTTP listener
--cleanup-unauthed Cleanup unauthed SSH connections after a set timeout (default true)
--cleanup-unauthed-timeout duration Duration to wait before cleaning up an unauthed connection (default 5s)
--cleanup-unbound Cleanup unbound (unforwarded) SSH connections after a set timeout
--cleanup-unbound-timeout duration Duration to wait before cleaning up an unbound (unforwarded) connection (default 5s)
-c, --config string Config file (default "config.yml")
--debug Enable debugging information
--debug-interval duration Duration to wait between each debug loop output if debug is true (default 2s)
-d, --domain string The root domain for HTTP(S) multiplexing that will be appended to subdomains (default "ssi.sh")
--force-all-https Redirect all requests to the https server
--force-https Allow indiviual binds to request for https to be enforced
--force-requested-aliases Force the aliases used to be the one that is requested. Will fail the bind if it exists already
--force-requested-ports Force the ports used to be the one that is requested. Will fail the bind if it exists already
--force-requested-subdomains Force the subdomains used to be the one that is requested. Will fail the bind if it exists already
--force-tcp-address Force the address used for the TCP interface to be the one defined by --tcp-address
--geodb Use a geodb to verify country IP address association for IP filtering
-h, --help help for sish
-i, --http-address string The address to listen for HTTP connections (default "localhost:80")
--http-load-balancer Enable the HTTP load balancer (multiple clients can bind the same domain)
--http-port-override int The port to use for http command output. This does not affect ports used for connecting, it's for cosmetic use only
--http-request-port-override int The port to use for http requests. Will default to 80, then http-port-override. Otherwise will use this value
--https Listen for HTTPS connections. Requires a correct --https-certificate-directory
-t, --https-address string The address to listen for HTTPS connections (default "localhost:443")
-s, --https-certificate-directory string The directory containing HTTPS certificate files (name.crt and name.key). There can be many crt/key pairs (default "deploy/ssl/")
--https-certificate-directory-watch-interval duration The interval to poll for filesystem changes for HTTPS certificates (default 200ms)
--https-ondemand-certificate Enable retrieving certificates on demand via Let's Encrypt
--https-ondemand-certificate-accept-terms Accept the Let's Encrypt terms
--https-ondemand-certificate-email string The email to use with Let's Encrypt for cert notifications. Can be left blank
--https-port-override int The port to use for https command output. This does not affect ports used for connecting, it's for cosmetic use only
--https-request-port-override int The port to use for https requests. Will default to 443, then https-port-override. Otherwise will use this value
--idle-connection Enable connection idle timeouts for reads and writes (default true)
--idle-connection-timeout duration Duration to wait for activity before closing a connection for all reads and writes (default 5s)
--load-templates Load HTML templates. This is required for admin/service consoles (default true)
--load-templates-directory string The directory and glob parameter for templates that should be loaded (default "templates/*")
--localhost-as-all Enable forcing localhost to mean all interfaces for tcp listeners (default true)
--log-to-client Enable logging HTTP and TCP requests to the client
--log-to-file Enable writing log output to file, specified by log-to-file-path
--log-to-file-compress Enable compressing log output files
--log-to-file-max-age int The maxium number of days to store log output in a file (default 28)
--log-to-file-max-backups int The maxium number of rotated logs files to keep (default 3)
--log-to-file-max-size int The maximum size of outputed log files in megabytes (default 500)
--log-to-file-path string The file to write log output to (default "/tmp/sish.log")
--log-to-stdout Enable writing log output to stdout (default true)
--ping-client Send ping requests to the underlying SSH client.
This is useful to ensure that SSH connections are kept open or close cleanly (default true)
--ping-client-interval duration Duration representing an interval to ping a client to ensure it is up (default 5s)
--ping-client-timeout duration Duration to wait for activity before closing a connection after sending a ping to a client (default 5s)
-n, --port-bind-range string Ports or port ranges that sish will allow to be bound when a user attempts to use TCP forwarding (default "0,1024-65535")
-p, --private-key-passphrase string Passphrase to use to encrypt the server private key (default "S3Cr3tP4$$phrAsE")
-l, --private-keys-directory string The location of other SSH server private keys. sish will add these as valid auth methods for SSH. Note, these need to be unencrypted OR use the private-key-passphrase (default "deploy/keys")
--proxy-protocol Use the proxy-protocol while proxying connections in order to pass-on IP address and port information
--proxy-protocol-listener Use the proxy-protocol to resolve ip addresses from user connections
--proxy-protocol-policy string What to do with the proxy protocol header. Can be use, ignore, reject, or require (default "use")
--proxy-protocol-timeout duration The duration to wait for the proxy proto header (default 200ms)
--proxy-protocol-use-timeout Use a timeout for the proxy-protocol read
-q, --proxy-protocol-version string What version of the proxy protocol to use. Can either be 1, 2, or userdefined.
If userdefined, the user needs to add a command to SSH called proxyproto=version (ie proxyproto=1) (default "1")
--redirect-root Redirect the root domain to the location defined in --redirect-root-location (default true)
-r, --redirect-root-location string The location to redirect requests to the root domain
to instead of responding with a 404 (default "https://github.com/antoniomika/sish")
--rewrite-host-header Force rewrite the host header if the user provides host-header=host.com (default true)
--service-console Enable the service console for each service and send the info to connected clients
--service-console-max-content-length int The max content length before we stop reading the response body (default -1)
-m, --service-console-token string The token to use for service console access. Auto generated if empty for each connected tunnel
--sni-load-balancer Enable the SNI load balancer (multiple clients can bind the same SNI domain/port)
--sni-proxy Enable the use of SNI proxying
--sni-proxy-https Enable the use of SNI proxying on the HTTPS port
-a, --ssh-address string The address to listen for SSH connections (default "localhost:2222")
--strip-http-path Strip the http path from the forward (default true)
--tcp-address string The address to listen for TCP connections
--tcp-aliases Enable the use of TCP aliasing
--tcp-aliases-allowed-users any Enable setting allowed users to access tcp aliases.
Can provide tcp-aliases-allowed-users in the ssh command set to a comma separated list of ssh fingerprints that can access an alias.
Provide any for all.
--tcp-load-balancer Enable the TCP load balancer (multiple clients can bind the same port)
--time-format string The time format to use for both HTTP and general log messages (default "2006/01/02 - 15:04:05")
--verify-dns Verify DNS information for hosts and ensure it matches a connecting users sha256 key fingerprint (default true)
--verify-ssl Verify SSL certificates made on proxied HTTP connections (default true)
-v, --version version for sish
-y, --whitelisted-countries string A comma separated list of whitelisted countries. Applies to HTTP, TCP, and SSH connections
-w, --whitelisted-ips string A comma separated list of whitelisted ips. Applies to HTTP, TCP, and SSH connections
```
```

26
docs/posts/faq.md Normal file
View File

@@ -0,0 +1,26 @@
---
title: FAQ
description: Frequently asked questions for sish
keywords: [sish, faq]
---
# Where can I find latest releases?
Builds are made automatically for each commit to the repo and are pushed to
Dockerhub. Builds are tagged using a commit sha, branch name, tag, `latest` if
released on `main`.
- [Image Registry](https://hub.docker.com/r/antoniomika/sish/tags)
- [OS/arch binaries](https://github.com/antoniomika/sish/releases)
# How does sish compare to ngrok?
The goals are similar, but the underlying tech is different. With `sish` the
end-user doesn't need to install any cli tool in order to use it. We are simply
leveraging SSH to make the connections that the `ngrok` cli would use.
# Who can I contact with questions?
If you have any questions or comments, feel free to reach out via email
[me@antoniomika.me](mailto:me@antoniomika.me) or on libera IRC
[#sish](https://web.libera.chat/#sish)

View File

@@ -0,0 +1,124 @@
---
title: Forwarding Types
description: The various forwarding types sish supports
keywords: [sish, forwarding, types, http, tcp, sni, alias]
---
# HTTP
sish can forward any number of HTTP connections through SSH. It also provides
logging the connections to the connected client that has forwarded the
connection and a web interface to see full request and responses made to each
forwarded connection. Each webinterface can be unique to the forwarded
connection or use a unified access token. To make use of HTTP forwarding, ports
`[80, 443]` are used to tell sish that a HTTP connection is being forwarded and
that HTTP virtualhosting should be defined for the service. For example, let's
say I'm developing a HTTP webservice on my laptop at port `8080` that uses
websockets and I want to show one of my coworkers who is not near me. I can
forward the connection like so:
```bash
ssh -R hereiam:80:localhost:8080 tuns.sh
```
And then share the link `https://hereiam.tuns.sh` with my coworker. They should
be able to access the service seamlessly over HTTPS, with full websocket support
working fine. Let's say `hereiam.tuns.sh` isn't available, then sish will
generate a random subdomain and give that to me.
# TCP
Any TCP based service can be used with sish for TCP and alias forwarding. TCP
forwarding will establish a remote port on the server that you deploy sish to
and will forward all connections to that port through the SSH connection and to
your local device. For example, if I was to run a SSH server on my laptop with
port `22` and want to be able to access it from anywhere at `tuns.sh:2222`, I
can use an SSH command on my laptop like so to forward the connection:
```bash
ssh -R 2222:localhost:22 tuns.sh
```
I can use the forwarded connection to then access my laptop from anywhere:
```bash
ssh -p 2222 tuns.sh
```
# TCP Alias
Let's say instead I don't want the service to be accessible by the rest of the
world, you can then use a TCP alias. A TCP alias is a type of forwarded TCP
connection that only exists inside of sish. You can gain access to the alias by
using SSH with the `-W` flag, which will forwarding the SSH process'
stdin/stdout to the fowarded TCP connection. In combination with authentication,
this will guarantee your remote service is safe from the rest of the world
because you need to login to sish before you can access it. Changing the example
above for this would mean running the following command on my laptop:
```bash
ssh -R mylaptop:22:localhost:22 tuns.sh
```
sish won't publish port 22 or 2222 to the rest of the world anymore, instead
it'll retain a pointer saying that TCP connections made from within SSH after a
user has authenticated to `mylaptop:22` should be forwarded to the forwarded TCP
tunnel. Then I can use the forwarded connection access my laptop from anywhere
using:
```bash
ssh -o ProxyCommand="ssh -W %h:%p tuns.sh" mylaptop
```
Shorthand for which is this with newer SSH versions:
```bash
ssh -J tuns.sh mylaptop
```
You can also use TCP aliases with any port you would like. If for example you
wanted to use an alias with port `80` or `443` (default to a HTTP tunnel),
provide the command `tcp-alias=true` to the ssh command:
```bash
ssh -R service:80:localhost:80 tuns.sh tcp-alias=true
```
Aliases can be accessed on a different computer using SSH local forwards also.
For the above, I could use:
```bash
ssh -L 80:service:80 tuns.sh
```
to then access the forwarded server service at `localhost:80` on the client side
of the computer I am on.
# SNI
Sometimes, you may have multiple TCP services running on the same port. If these
services support [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication),
you can have sish route TLS connections to different backends based on the SNI
name provided. For example, I have two webservices (servers) and I want to
offload TLS to each without sish offloading SSL. This can be achieved by
disabling sish's internal HTTPS service (you won't be able to use the service
console for this however). Then, I can start a ssh connection from each server
like so:
From server A
```bash
ssh -R servera.example.com:443:localhost:443 tuns.sh sni-proxy=true
```
From server B
```bash
ssh -R serverb.example.com:443:localhost:443 tuns.sh sni-proxy=true
```
As long as server{a,b}.example.com points to where sish is hosted and a user can
bind those hosts, TLS connections to servera.example.com:443 will be forwarded
to server A and TLS connections to serverb.example.com:443 will be forwarded to
server B. It is then up to each server to complete the TLS handshake and the
subsequent request.

View File

@@ -0,0 +1,155 @@
---
title: Getting Started
description: Learn how to use sish
keywords: [sish, guide, getting, started, how]
---
We have a managed service and **three** officially supported self-hosting
deployments for `sish`.
Here are the guides related to self-hosting `sish`.
# Managed
The easiest way to get started with using sish is to use our managed service at
[tuns.sh](https://tuns.sh). This service manages `sish` for you so you don't
have to go through the process of setting `sish` up yourself.
# DNS
To use sish, you need to add a wildcard DNS record that is used for multiplexed
subdomains. Adding an `A` record with `*` as the subdomain to the IP address of
your server is the simplest way to achieve this configuration.
For the purposes of our guides, we will use `tuns.sh` as our domain.
# Docker Compose
You can use Docker Compose to setup your sish instance. This includes taking
care of SSL via Let's Encrypt for you. This uses the
[adferrand/dnsrobocert](https://github.com/adferrand/dnsrobocert) container to
handle issuing wildcard certifications over DNS. For more information on how to
use this, head to that link above.
We use
[sish/deploy](https://github.com/antoniomika/sish/tree/4ed42082289f6da8a9f873ed8110963290ea4ce9/deploy)
in our deployment of `tuns.sh` and are using them for this guide.
Clone the `sish` repo:
```bash
git clone git@github.com:antoniomika/sish.git
```
Then copy the `sish/deploy` folder:
```bash
cp -R sish/deploy ~/sish
```
Edit `~/sish/docker-compose.yml` and `~/sish/le-config.yml` file with your
domain and DNS auth info.
Then, create a symlink that points to your domain's Let's Encrypt certificates
like:
```bash
ln -s /etc/letsencrypt/live/<your domain>/fullchain.pem deploy/ssl/<your domain>.crt
ln -s /etc/letsencrypt/live/<your domain>/privkey.pem deploy/ssl/<your domain>.key
```
> Careful: the symlinks need to point to `/etc/letsencrypt`, not a relative
> path. The symlinks will not resolve on the host filesystem, but they will
> resolve inside of the sish container because it mounts the letsencrypt files
> in /etc/letsencrypt, _not_ ./letsencrypt.
Finally, you can deploy your service like so:
```bash
docker-compose -f deploy/docker-compose.yml up -d
```
SSH to your host to communicate with sish
```bash
ssh -p 2222 -R 80:localhost:8080 tuns.sh
```
# Docker
[Find our latest releases.](/releases)
Pull the Docker image
```bash
docker pull antoniomika/sish:latest
```
Create folders to host your keys
```bash
mkdir -p ~/sish/ssl ~/sish/keys ~/sish/pubkeys
```
Copy your public keys to `pubkeys`
```bash
cp ~/.ssh/id_ed25519.pub ~/sish/pubkeys
```
Run the image
```bash
docker run -itd --name sish \
-v ~/sish/ssl:/ssl \
-v ~/sish/keys:/keys \
-v ~/sish/pubkeys:/pubkeys \
--net=host antoniomika/sish:latest \
--ssh-address=:2222 \
--http-address=:80 \
--https-address=:443 \
--https=true \
--https-certificate-directory=/ssl \
--authentication-keys-directory=/pubkeys \
--private-keys-directory=/keys \
--bind-random-ports=false \
--domain=tuns.sh
```
SSH to your host to communicate with sish
```bash
ssh -p 2222 -R 80:localhost:8080 tuns.sh
```
# Google Cloud Platform
There is a tutorial for creating an instance in Google Cloud Platform with sish
fully setup that can be found
[here](https://github.com/antoniomika/sish/blob/main/deploy/gcloud.md). It can
be accessed through [Google Cloud Shell](https://cloud.google.com/shell).
[![Open in Cloud Shell](https://gstatic.com/cloudssh/images/open-btn.svg)](https://ssh.cloud.google.com/cloudshell/editor?shellonly=true&cloudshell_git_repo=https%3A%2F%2Fgithub.com%2Fantoniomika%2Fsish&cloudshell_git_branch=main&cloudshell_tutorial=deploy%2Fgcloud.md)
# Authentication
If you want to use this service privately, it supports both public key and
password authentication. To enable authentication, set `--authentication=true`
as one of your CLI options and be sure to configure `--authentication-password`
or `--authentication-keys-directory` to your liking. The directory provided by
`--authentication-keys-directory` is watched for changes and will reload the
authorized keys automatically. The authorized cert index is regenerated on
directory modification, so removed public keys will also automatically be
removed. Files in this directory can either be single key per file, or multiple
keys per file separated by newlines, similar to `authorized_keys`. Password auth
can be disabled by setting `--authentication-password=""` as a CLI option.
One of my favorite ways of using this for authentication is like so:
```bash
sish@sish0:~/sish/pubkeys# curl https://github.com/antoniomika.keys > antoniomika
```
This will load my public keys from GitHub, place them in the directory that sish
is watching, and then load the pubkey. As soon as this command is run, I can SSH
normally and it will authorize me.

6
docs/posts/home.md Normal file
View File

@@ -0,0 +1,6 @@
---
title: sish
description: something something darkside
slug: index
template: home.page.tmpl
---

View File

@@ -0,0 +1,78 @@
---
title: How it works
description: Technical details for sish
keywords: [sish, how, works]
---
SSH can normally forward local and remote ports. This service implements an SSH
server that only handles forwarding and nothing else.
But let's first take a step back and illustrate some basic examples of how
things work without `sish`. Let's start with a simple port forward:
# Port Forward
Here Eric has a web server hosted on its `localhost:3000`. Eric has to forward
its localhost connection to Tony in order for him to access the web server.
<div class="hiw">
<img src="./hiw-port-forward.png" alt="hiw-port-forward" />
</div>
This is manual, arduous, and sometimes difficult to get to work properly because
of firewalls. So many people opt to setup a VPN that both Eric and Tony can
connect to.
# Traditional VPN
Now both Eric and Tony connect to the VPN service and then Tony can access
Eric's web server via Eric's VPN IP.
<div class="hiw">
<img src="./hiw-vpn.png" alt="hiw-vpn" />
</div>
Great! But this requires both Eric and Tony to connect to the VPN service. What
if Eric wants to share the web server with multiple users that are **not**
connected to the VPN? Sometimes it isn't feasible or appropriate to have
everyone connect to your VPN.
# sish Public
Enter `sish`. Using just SSH and a `sish` service, Eric can create an SSH remote
port forward to connect to `sish` which will automatically create a public URL
that **anyone** can access.
<div class="hiw">
<img src="./hiw-sish-public.png" alt="hiw-sish-public" />
</div>
Very nice! Tony doesn't have to worry about firewall issues, setting up and
connecting to a VPN, and anyone else can also access the web server via URL.
This is the real power of leveraging `sish`.
But what if we want the web server to be private so only Tony can access the web
server using `sish`?
# sish Private
In this example both Eric and Tony setup an SSH tunnel to `sish`:
- Eric sets up a remote port forward tunnel
- Tony sets up a local port forward tunnel
<div class="hiw">
<img src="./hiw-sish-private.png" alt="hiw-sish-private" />
</div>
> NOTE: The remote tunnel command needs to include `tcp-aliases-allowed-users` with
> Tony's pubkey fingerprint
```bash
ssh -R private:3000:localhost:3000 tuns.sh tcp-aliases-allowed-users=SHA256:4vNGm4xvuVxYbaIE5JX1KgTgncaF3x3w2lk+JMLOfd8
```
This creates a private connection between Eric and Tony that allows Tony to
access Eric's local web server without anyone else having access to it!
[Learn more](/cheatsheet#https-private-access)

6
docs/posts/sitemap.md Normal file
View File

@@ -0,0 +1,6 @@
---
title: sitemap
description: sish doc sitemap
slug: sitemap
template: sitemap.page.tmpl
---

1
docs/public/.gitkeep Normal file
View File

@@ -0,0 +1 @@

File diff suppressed because it is too large Load Diff

BIN
docs/static/favicon-16x16.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

BIN
docs/static/favicon-32x32.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
docs/static/hiw-port-forward.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
docs/static/hiw-sish-private.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
docs/static/hiw-sish-public.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
docs/static/hiw-vpn.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

90
docs/static/main.css vendored Normal file
View File

@@ -0,0 +1,90 @@
.sitemap {
column-count: 2;
}
.hiw {
background-color: #282a36;
}
.link-alt-adj,
.link-alt-adj:visited,
.link-alt-adj:visited:hover,
.link-alt-adj:hover {
color: var(--link-color);
text-decoration: none;
}
.link-alt-adj:visited:hover,
.link-alt-adj:hover {
text-decoration: underline;
}
.link-alt-hover,
.link-alt-hover:visited,
.link-alt-hover:visited:hover,
.link-alt-hover:hover {
color: var(--hover);
text-decoration: none;
}
.link-alt-hover:visited:hover,
.link-alt-hover:hover {
text-decoration: underline;
}
.link-alt,
.link-alt:visited,
.link-alt:visited:hover,
.link-alt:hover {
color: var(--white);
text-decoration: none;
}
.link-alt:visited:hover,
.link-alt:hover {
text-decoration: underline;
}
.hero {
padding: 5rem 0;
}
.features {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(225px, 1fr));
gap: 1rem;
}
.features h3 {
border: none;
}
.mk-nav {
padding: 1rem;
}
.text-hdr {
color: var(--hover);
}
.text-underline-hdr {
border-bottom: 3px solid var(--hover);
padding-bottom: 3px;
}
.current {
background-color: var(--blockquote-bg) !important;
border-right: 5px solid var(--blockquote);
}
.current a {
color: var(--white);
}
.current-page a {
color: var(--white);
}
.pager {
min-width: 150px;
}

View File

@@ -0,0 +1,21 @@
{{define "base"}}
<!doctype html>
<html lang="en">
<head>
<title>{{template "title" .}}</title>
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="keywords" content="ngrok, sish, ssh, tunnel, self-hosted" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="stylesheet" href="https://pico.sh/syntax.css" />
<link rel="stylesheet" href="https://pico.sh/smol.css" />
<link rel="stylesheet" href="/main.css" />
{{template "meta" .}}
</head>
<body {{template "attrs" .}}>
{{template "body" .}}
</body>
</html>
{{end}}

View File

@@ -0,0 +1,5 @@
{{define "footer"}}
<footer>
<p>Built by <strong>Antonio Mika</strong></p>
</footer>
{{end}}

61
docs/tmpl/home.page.tmpl Normal file
View File

@@ -0,0 +1,61 @@
{{template "base" .}}
{{define "title"}}{{.Data.Title}}{{end}}
{{define "meta"}}
{{end}}
{{define "attrs"}}class="container"{{end}}
{{define "body"}}
{{template "nav" .}}
<main>
<div class="flex flex-col gap-2">
<div class="flex items-center justify-center hero">
<div class="flex flex-col items-center gap-2">
<h1 class="logo-header text-2xl">sish</h1>
<div class="text-center text-lg">Access localhost using https</div>
<a href="/getting-started" class="btn-link">GET STARTED</a>
</div>
</div>
<article class="features">
<div class="box">
<h2 class="m-0 p-0 text-lg">
Tunnels to localhost using SSH
</h2>
<p>Using SSH tunnels, we can forward requests to your localhost from <a href="/forwarding-types">https, wss, and tcp</a>.</p>
</div>
<div class="box">
<h2 class="m-0 p-0 text-lg">
Self-hosted ngrok alternative
</h2>
<p>With docker it is easier than ever to deploy <code>sish</code> to your own VM.</p>
</div>
<div class="box">
<h2 class="m-0 p-0 text-lg">
Fully managed service <a href="https://tuns.sh">tuns.sh</a>
</h2>
<p>We also manage an instance of <code>sish</code> so users don't have to worry about managing it.</p>
</div>
</article>
<article>
<div class="hiw">
<img src="./hiw-sish-public.png" alt="hiw-sish-public" />
</div>
<div class="flex justify-center">
<a href="/how-it-works" class="mt-4 btn-link">LEARN MORE</a>
</div>
</article>
</div>
<hr class="my-4" />
{{template "footer" .}}
</main>
{{end}}

View File

@@ -0,0 +1,18 @@
{{define "nav"}}
<nav class="mk-nav">
<div class="flex items-center justify-center gap-2 text-md">
<a href="/" class="link-alt">
sish
</a>
<a href="/sitemap" class="link-alt">
sitemap
</a>
<a href="https://github.com/antoniomika/sish" class="link-alt">
github
</a>
<a href="https://web.libera.chat/#sish" class="link-alt">
irc
</a>
</div>
</nav>
{{end}}

62
docs/tmpl/post.page.tmpl Normal file
View File

@@ -0,0 +1,62 @@
{{template "base" .}}
{{define "title"}}{{.Data.Title}}{{end}}
{{define "meta"}}{{end}}
{{define "attrs"}}class="container-sm"{{end}}
{{define "body"}}
{{template "nav" .}}
<main class="post">
<h1 class="text-2xl text-underline-hdr text-hdr inline-block">{{.Data.Title}}</h1>
<h2 class="text-xl">{{.Data.Description}}</h2>
<hr />
<article class="md">
{{.Data.Html}}
</article>
<div class="flex justify-between gap-2 my-4">
{{if .Prev}}
<div class="pager max-w-half flex items-center">
<div class="flex flex-col items-start">
<div class="text-sm font-grey-light">&lt;&lt; PREV</div>
<a href="{{.Prev.GenHref}}" class="text-xl link-alt-adj">{{.Prev.Text}}</a>
</div>
</div>
{{end}}
{{if .Next}}
<div class="pager max-w-half flex items-center justify-end">
<div class="flex flex-col items-end">
<div class="text-sm font-grey-light">
NEXT &gt;&gt;
</div>
<a href="{{.Next.GenHref}}" class="text-xl align-right link-alt-adj">{{.Next.Text}}</a>
</div>
</div>
{{end}}
</div>
</main>
<div class="sitemap text-sm mb-4 text-center">
{{range .Sitemap -}}
<div>
{{- if (and $.Prev (eq $.Prev.GenHref .GenHref)) -}}
<a href="{{.GenHref}}" class="link-alt-adj">{{.Text}}</a>
{{- else if (and $.Next (eq $.Next.GenHref .GenHref)) -}}
<a href="{{.GenHref}}" class="link-alt-adj">{{.Text}}</a>
{{- else if (eq $.Href .GenHref) -}}
<a href="{{.GenHref}}" class="link-alt-hover">{{.Text}}</a>
{{- else -}}
<a href="{{.GenHref}}" class="link-alt">{{.Text}}</a>
{{- end -}}
</div>
{{- end}}
</div>
{{template "footer" .}}
{{end}}

View File

@@ -0,0 +1,22 @@
{{template "base" .}}
{{define "title"}}{{.Data.Title}}{{end}}
{{define "meta"}}{{end}}
{{define "attrs"}}class="container-sm"{{end}}
{{define "body"}}
{{template "nav" .}}
<main>
<h1 class="text-2xl text-underline-hdr text-hdr inline-block">{{.Data.Title}}</h1>
<h2 class="text-xl">{{.Data.Description}}</h2>
<hr />
{{template "toc" .}}
</main>
{{template "footer" .}}
{{end}}

View File

@@ -0,0 +1,14 @@
{{define "toc"}}
<div>
{{range $key, $value := .SitemapByTag}}
<div class="box my">
<h2 class="text-xl">{{$key}}</h2>
<ul>
{{range $value}}
<li><a href="{{.GenHref}}">{{.Text}}</a></li>
{{end}}
</ul>
</div>
{{end}}
</div>
{{end}}

7
go.mod
View File

@@ -12,6 +12,7 @@ require (
github.com/jpillora/ipfilter v1.2.9
github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a
github.com/picosh/pdocs v0.0.0-20240122053603-749f8ca95244
github.com/pires/go-proxyproto v0.7.0
github.com/radovskyb/watcher v1.0.7
github.com/sirupsen/logrus v1.9.3
@@ -24,10 +25,12 @@ require (
require (
github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
github.com/alecthomas/chroma v0.10.0 // indirect
github.com/bytedance/sonic v1.10.2 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.1 // indirect
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
@@ -61,7 +64,11 @@ require (
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/yuin/goldmark v1.6.0 // indirect
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 // indirect
github.com/yuin/goldmark-meta v1.1.0 // indirect
github.com/zeebo/blake3 v0.2.3 // indirect
go.abhg.dev/goldmark/anchor v0.1.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/arch v0.7.0 // indirect

15
go.sum
View File

@@ -6,6 +6,8 @@ github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXY
github.com/ScaleFT/sshkeys v1.2.0 h1:5BRp6rTVIhJzXT3VcUQrKgXR8zWA3sOsNeuyW15WUA8=
github.com/ScaleFT/sshkeys v1.2.0/go.mod h1:gxOHeajFfvGQh/fxlC8oOKBe23xnnJTif00IFFbiT+o=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
github.com/antoniomika/oxy v1.1.1-0.20210804032133-5924ea01c950 h1:AZcTu5Wwh+MJqW+m4eA+Bv9H9VV4xedv+lElnCfM1k0=
github.com/antoniomika/oxy v1.1.1-0.20210804032133-5924ea01c950/go.mod h1:pJou3S+yPP9m4CrgeBtKj/4gl31Kbte2j5JS1iP0WVc=
github.com/antoniomika/syncmap v1.0.0 h1:iFSfbQFQOvHZILFZF+hqWosO0no+W9+uF4y2VEyMKWU=
@@ -31,6 +33,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a h1:saTgr5tMLFnmy/yg3qDTft4rE5DY2uJ/cCxCe3q0XTU=
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a/go.mod h1:Bw9BbhOJVNR+t0jCqx2GC6zv0TGBsShs56Y3gfSCvl0=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
@@ -119,6 +123,8 @@ github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdU
github.com/phuslu/iploc v1.0.20230201/go.mod h1:gsgExGWldwv1AEzZm+Ki9/vGfyjkL33pbSr9HGpt2Xg=
github.com/phuslu/iploc v1.0.20231229 h1:zZVEFTAJu7tQIKssTPtUomSqjpBjI32t44q37Zu3S7E=
github.com/phuslu/iploc v1.0.20231229/go.mod h1:gsgExGWldwv1AEzZm+Ki9/vGfyjkL33pbSr9HGpt2Xg=
github.com/picosh/pdocs v0.0.0-20240122053603-749f8ca95244 h1:XMmcHS9/Je4ngtVy4+Dih4+1ohPtukPCOWgX+R3NYBk=
github.com/picosh/pdocs v0.0.0-20240122053603-749f8ca95244/go.mod h1:rh8n5EosoD8svAbVPUEuXWfcWBsGj3GPeG/8D/0Az3c=
github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs=
github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -173,12 +179,21 @@ github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/vulcand/predicate v1.1.0/go.mod h1:mlccC5IRBoc2cIFmCB8ZM62I3VDb6p2GXESMHa3CnZg=
github.com/yuin/goldmark v1.4.5/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68=
github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 h1:yHfZyN55+5dp1wG7wDKv8HQ044moxkyGq12KFFMFDxg=
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594/go.mod h1:U9ihbh+1ZN7fR5Se3daSPoz1CGF9IYtSvWwVQtnzGHU=
github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc=
github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0=
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ=
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
go.abhg.dev/goldmark/anchor v0.1.1 h1:NUH3hAzhfeymRqZKOkSoFReZlEAmfXBZlbXEzpD2Qgc=
go.abhg.dev/goldmark/anchor v0.1.1/go.mod h1:zYKiaHXTdugwVJRZqInVdmNGQRM3ZRJ6AGBC7xP7its=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=