mirror of
https://github.com/antoniomika/sish.git
synced 2025-09-26 19:21:15 +08:00
feat: docs site (#286)
* feat: docs site * docs: copy * chore(docs): update cli post * revert * chore: go.mod
This commit is contained in:
27
.github/workflows/docs.yml
vendored
Normal file
27
.github/workflows/docs.yml
vendored
Normal 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
2
.gitignore
vendored
@@ -2,3 +2,5 @@ deploy/
|
||||
dist/
|
||||
sish
|
||||
__debug_bin
|
||||
docs/public/*
|
||||
!docs/public/.gitkeep
|
||||
|
21
Makefile
Normal file
21
Makefile
Normal 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
418
README.md
@@ -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).
|
||||
|
||||
[](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
|
||||
|
@@ -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
94
docs/cmd/ssg.go
Normal 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
81
docs/posts/advanced.md
Normal 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
121
docs/posts/cheatsheet.md
Normal 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
130
docs/posts/cli.md
Normal 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
26
docs/posts/faq.md
Normal 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)
|
124
docs/posts/forwarding-types.md
Normal file
124
docs/posts/forwarding-types.md
Normal 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.
|
155
docs/posts/getting-started.md
Normal file
155
docs/posts/getting-started.md
Normal 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).
|
||||
|
||||
[](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
6
docs/posts/home.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
title: sish
|
||||
description: something something darkside
|
||||
slug: index
|
||||
template: home.page.tmpl
|
||||
---
|
78
docs/posts/how-it-works.md
Normal file
78
docs/posts/how-it-works.md
Normal 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
6
docs/posts/sitemap.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
title: sitemap
|
||||
description: sish doc sitemap
|
||||
slug: sitemap
|
||||
template: sitemap.page.tmpl
|
||||
---
|
1
docs/public/.gitkeep
Normal file
1
docs/public/.gitkeep
Normal file
@@ -0,0 +1 @@
|
||||
|
2509
docs/sish-diagrams.excalidraw
Normal file
2509
docs/sish-diagrams.excalidraw
Normal file
File diff suppressed because it is too large
Load Diff
BIN
docs/static/favicon-16x16.png
vendored
Normal file
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
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
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
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
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
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
90
docs/static/main.css
vendored
Normal 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;
|
||||
}
|
21
docs/tmpl/base.layout.tmpl
Normal file
21
docs/tmpl/base.layout.tmpl
Normal 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}}
|
5
docs/tmpl/footer.partial.tmpl
Normal file
5
docs/tmpl/footer.partial.tmpl
Normal 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
61
docs/tmpl/home.page.tmpl
Normal 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}}
|
18
docs/tmpl/nav.partial.tmpl
Normal file
18
docs/tmpl/nav.partial.tmpl
Normal 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
62
docs/tmpl/post.page.tmpl
Normal 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"><< 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 >>
|
||||
</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}}
|
22
docs/tmpl/sitemap.page.tmpl
Normal file
22
docs/tmpl/sitemap.page.tmpl
Normal 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}}
|
14
docs/tmpl/toc.partial.tmpl
Normal file
14
docs/tmpl/toc.partial.tmpl
Normal 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
7
go.mod
@@ -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
15
go.sum
@@ -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=
|
||||
|
Reference in New Issue
Block a user