Skip to content

Commit

Permalink
Update letsencypt documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
antoniomika committed May 2, 2020
1 parent 8a5950f commit ed9f54f
Show file tree
Hide file tree
Showing 11 changed files with 93 additions and 151 deletions.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
deploy/
!deploy/*/.gitkeep
!deploy/docker-compose.yml
dist/
sish
__debug_bin
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"--http-address=:8081",
"--ssh-address=:2222",
"--domain=testing.ssi.sh",
"--force-random-subdomain=false",
"--bind-random-subdomains=false",
"--bind-random-ports=false",
"--enable-https=false",
"--enable-authentication=false",
Expand Down
152 changes: 43 additions & 109 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ An open source serveo/ngrok alternative.
Deploy
------

Builds are made automatically on Google Cloud Build and Dockerhub. Feel free to either use the automated binaries or to build your own. If you submit a PR and would like access to Google Cloud Build's output (including pre-made PR binaries), feel free to let me know.
Builds are made automatically on Google Cloud Build and Dockerhub. Feel free to
either use the automated binaries or to build your own. If you submit a PR and
would like access to Google Cloud Build's output (including pre-made PR binaries), feel free to let me know.

1. Pull the Docker image
- `docker pull antoniomika/sish:latest`
Expand All @@ -18,14 +20,14 @@ Builds are made automatically on Google Cloud Build and Dockerhub. Feel free to
-v ~/sish/keys:/keys \
-v ~/sish/pubkeys:/pubkeys \
--net=host antoniomika/sish:latest \
-sish.addr=:22 \
-sish.https=:443 \
-sish.http=:80 \
-sish.httpsenabled=true \
-sish.httpspems=/ssl \
-sish.keysdir=/pubkeys \
-sish.pkloc=/keys/ssh_key \
-sish.bindrandom=false
--ssh-address=:22 \
--http-address=:80 \
--https-address=:443 \
--enable-https=true \
--certificate-directory=/ssl \
--authentication-keys-directory=/pubkeys \
--private-key-location=/keys/ssh_key \
--bind-random-ports=false
```

3. SSH to your host to communicate with sish
Expand All @@ -34,20 +36,24 @@ Builds are made automatically on Google Cloud Build and Dockerhub. Feel free to
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/docker-letsencrypt-dns](https://github.com/adferrand/docker-letsencrypt-dns) 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:
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:
```bash
DOMAIN=yourdomain.com \
[email protected] \
LEXICON_PROVIDER=cloudflare \
LEXICON_PROVIDER_OPTIONS="[email protected] --auth-token=your-auth-token" \
docker-compose -f deploy/docker-compose.yml up -d
```
How it works
------------
SSH can normally forward local and remote ports. This service implements an SSH server that only does that 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 connections, but only if that port is available.
SSH can normally forward local and remote ports. This service implements
an SSH server that only does that 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 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 `-sish.forcerandomsubdomain` option to `false` and then selecting a
Expand All @@ -60,21 +66,30 @@ If the selected subdomain is not taken, it will be assigned to your connection.
Authentication
--------------
If you want to use this service privately, it supports both public key and password authentication. To enable authentication, set `-sish.auth=true` as one of your CLI options and be sure to configure `-sish.password` or `-sish.keysdir` to your liking. The directory provided by `-sish.keysdir` 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 `-sish.password=""` as a CLI option.
If you want to use this service privately, it supports both public key and password
authentication. To enable authentication, set `-sish.auth=true` as one of your CLI
options and be sure to configure `-sish.password` or `-sish.keysdir` to your liking.
The directory provided by `-sish.keysdir` 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 `-sish.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.
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.
Whitelisting IPs
----------------
Whitelisting IP ranges or countries is also possible. Whole CIDR ranges can be
specified with the `-sish.whitelistedips` 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
specified with the `-sish.whitelistedips` 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 `sish.whitelistedcountries` with a comma-separated
Expand All @@ -84,7 +99,15 @@ need to set `-sish.usegeodb` to `true`.
Demo - At this time, the demo instance has been set to require auth due to abuse
----

There is a demo service (and my private instance) currently running on `ssi.sh` that doesn't require any authentication. This service provides default logging (errors, connection IP/username, and pubkey fingerprint). I do not log any of the password authentication data or the data sent within the service/tunnels. My deploy uses the exact deploy steps that are listed above. This instance is for testing and educational purposes only. You can deploy this extremely easily on any host (Google Cloud Platform provides an always-free instance that this should run perfectly on). If the service begins to accrue a lot of traffic, I will enable authentication and then you can reach out to me to get your SSH key whitelisted (make sure it's on GitHub and you provide me with your GitHub username).
There is a demo service (and my private instance) currently running on `ssi.sh` that
doesn't require any authentication. This service provides default logging
(errors, connection IP/username, and pubkey fingerprint). I do not log any of the password
authentication data or the data sent within the service/tunnels. My deploy uses the exact
deploy steps that are listed above. This instance is for testing and educational purposes only.
You can deploy this extremely easily on any host (Google Cloud Platform provides an always-free
instance that this should run perfectly on). If the service begins to accrue a lot of traffic,
I will enable authentication and then you can reach out to me to get your SSH key whitelisted
(make sure it's on GitHub and you provide me with your GitHub username).

Notes
-----
Expand All @@ -98,94 +121,5 @@ CLI Flags
---------
```text
sh-3.2# ./sish -h
Usage of ./sish:
-sish.addr string
The address to listen for SSH connections (default "localhost:2222")
-sish.adminenabled
Whether or not to enable the admin console
-sish.admintoken string
The token to use for admin access (default "S3Cr3tP4$$W0rD")
-sish.appendusertosubdomain
Whether or not to append the user to the subdomain
-sish.auth
Whether or not to require auth on the SSH service
-sish.bannedcountries string
A comma separated list of banned countries
-sish.bannedips string
A comma separated list of banned ips
-sish.bannedsubdomains string
A comma separated list of banned subdomains (default "localhost")
-sish.bindrandom
Bind ports randomly (OS chooses) (default true)
-sish.bindrange string
Ports that are allowed to be bound (default "0,1024-65535")
-sish.cleanupunbound
Whether or not to cleanup unbound (forwarded) SSH connections (default true)
-sish.debug
Whether or not to print debug information
-sish.domain string
The domain for HTTP(S) multiplexing (default "ssi.sh")
-sish.forcerandomsubdomain
Whether or not to force a random subdomain (default true)
-sish.http string
The address to listen for HTTP connections (default "localhost:80")
-sish.httpport int
The port to use for http command output
-sish.https string
The address to listen for HTTPS connections (default "localhost:443")
-sish.httpsenabled
Whether or not to listen for HTTPS connections
-sish.httpspems string
The location of pem files for HTTPS (fullchain.pem and privkey.pem) (default "ssl/")
-sish.httpsport int
The port to use for https command output
-sish.idletimeout int
Number of seconds to wait for activity before closing a connection (default 5)
-sish.connecttimeout int
Number of seconds the ssh login process is allowed before closing a connection (default 5)
-sish.keysdir string
Directory for public keys for pubkey auth (default "pubkeys/")
-sish.logtoclient
Whether or not to log http requests to the client
-sish.password string
Password to use for password auth (default "S3Cr3tP4$$W0rD")
-sish.pingclient
Whether or not ping the client. (default true)
-sish.pingclientinterval int
Interval in seconds to ping a client to ensure it is up. (default 10)
-sish.pkloc string
SSH server private key (default "keys/ssh_key")
-sish.pkpass string
Passphrase to use for the server private key (default "S3Cr3tP4$$phrAsE")
-sish.proxyprotoenabled
Whether or not to enable the use of the proxy protocol
-sish.proxyprotoversion 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")
-sish.redirectroot
Whether or not to redirect the root domain (default true)
-sish.redirectrootlocation string
Where to redirect the root domain to (default "https://github.com/antoniomika/sish")
-sish.serviceconsoleenabled
Whether or not to enable the admin console for each service and send the info to users
-sish.serviceconsoletoken string
The token to use for service access. Auto generated if empty.
-sish.subdomainlen int
The length of the random subdomain to generate (default 3)
-sish.tcpalias
Whether or not to allow the use of TCP aliasing
-sish.usegeodb
Whether or not to use the maxmind geodb
-sish.usersubdomainseparator
Separator to use when appending username to subdomain (default "-")
-sish.verifyorigin
Whether or not to verify origin on websocket connection (default true)
-sish.verifyssl
Whether or not to verify SSL on proxy connection (default true)
-sish.version
Print version and exit
-sish.whitelistedcountries string
A comma separated list of whitelisted countries
-sish.whitelistedips string
A comma separated list of whitelisted ips
```
4 changes: 2 additions & 2 deletions cmd/sish.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ func init() {
rootCmd.PersistentFlags().StringP("authentication-password", "u", "S3Cr3tP4$$W0rD", "Password to use for password auth")
rootCmd.PersistentFlags().StringP("authentication-keys-directory", "k", "deploy/pubkeys/", "Directory for public keys for pubkey auth")
rootCmd.PersistentFlags().StringP("port-bind-range", "n", "0,1024-65535", "Ports that are allowed to be bound")
rootCmd.PersistentFlags().StringP("proxy-protocol-version", "q", "1", "What version of the proxy protocol to use.\nCan either be 1, 2, or userdefined. If userdefined, the user needs to add a command to SSH called proxyproto:version (ie proxyproto:1)")
rootCmd.PersistentFlags().StringP("proxy-protocol-version", "q", "1", "What version of the proxy protocol to use.\nCan either be 1, 2, or userdefined. If userdefined, the user needs to add a command\nto SSH called proxyproto:version (ie proxyproto:1)")
rootCmd.PersistentFlags().StringP("admin-console-token", "j", "S3Cr3tP4$$W0rD", "The token to use for admin access")
rootCmd.PersistentFlags().StringP("service-console-token", "m", "", "The token to use for service access. Auto generated if empty.")
rootCmd.PersistentFlags().StringP("user-subdomain-separator", "", "", "The token to use for separating username and subdomains in a virtualhost.")

rootCmd.PersistentFlags().BoolP("force-random-subdomain", "", true, "Whether or not to force a random subdomain")
rootCmd.PersistentFlags().BoolP("bind-random-subdomains", "", true, "Whether or not to force a random subdomain")
rootCmd.PersistentFlags().BoolP("verify-origin", "", true, "Whether or not to verify origin on websocket connection")
rootCmd.PersistentFlags().BoolP("verify-ssl", "", true, "Whether or not to verify SSL on proxy connection")
rootCmd.PersistentFlags().BoolP("cleanup-unbound", "", true, "Whether or not to cleanup unbound (forwarded) SSH connections")
Expand Down
2 changes: 1 addition & 1 deletion config.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ enable-proxy-protocol: false
enable-redirect-root: true
enable-service-console: false
enable-tcp-aliases: false
force-random-subdomain: true
bind-random-subdomains: true
http-address: localhost:80
http-port-override: 0
https-address: localhost:443
Expand Down
35 changes: 12 additions & 23 deletions deploy/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,13 @@
version: '3.7'

services:
busybox:
image: busybox
volumes:
- ./letsencrypt:/etc/letsencrypt
command: /bin/sh -c "echo '$DOMAIN *.$DOMAIN autorestart-containers=sish' > /etc/letsencrypt/domains.conf"
letsencrypt:
image: adferrand/letsencrypt-dns:latest
image: adferrand/dnsrobocert:latest
container_name: letsencrypt-dns
depends_on:
- busybox
environment:
- VERSION=latest
- LETSENCRYPT_USER_MAIL
- LEXICON_PROVIDER
- LEXICON_PROVIDER_OPTIONS
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./letsencrypt:/etc/letsencrypt
- ./le-config.yml:/etc/dnsrobocert/config.yml
restart: always
sish:
image: antoniomika/sish:latest
Expand All @@ -30,15 +19,15 @@ services:
- ./pubkeys:/pubkeys
- ./keys:/keys
command: |
-sish.addr=:22
-sish.https=:443
-sish.http=:80
-sish.httpsenabled=true
-sish.httpspems=/etc/letsencrypt/live/$DOMAIN
-sish.keysdir=/pubkeys
-sish.pkloc=/keys/ssh_key
-sish.bindrandom=false
-sish.domain=$DOMAIN
-sish.forcerandomsubdomain=false
--ssh-address=:22
--http-address=:80
--https-address=:443
--enable-https=true
--certificate-directory=/etc/letsencrypt/live/ssi.sh
--authentication-keys-directory=/pubkeys
--private-key-location=/keys/ssh_key
--bind-random-ports=false
--bind-random-subdomains=false
--domain=ssi.sh
network_mode: host
restart: always
17 changes: 17 additions & 0 deletions deploy/le-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
acme:
email_account: AUTH_EMAIL
certificates:
- autorestart:
- containers:
- sish
domains:
- ssi.sh
- '*.ssi.sh'
name: ssi.sh
profile: cloudflare
profiles:
- name: cloudflare
provider: cloudflare
provider_options:
auth_token: AUTH_TOKEN
auth_username: AUTH_EMAIL
14 changes: 7 additions & 7 deletions templates/console.tmpl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{{ define "console" }}
{{ template "header" .}}
<div class="row">
<div class="col-md-6">
<div class="col-md-6 table-responsive">
<table id="request-table" class="table table-hover">
<thead class="thead-dark">
<tr>
Expand Down Expand Up @@ -73,20 +73,20 @@

var requestData = $(this).data("request-data");

$("#requestHeaders").html($("<pre/>").addClass("pre-scrollable").text(JSON.stringify(requestData.requestHeaders, null, 4))[0].outerHTML);
$("#requestHeaders").html($("<pre/>").addClass("pre-scrollable w-100").text(JSON.stringify(requestData.requestHeaders, null, 4))[0].outerHTML);

if ("Content-Type" in requestData.requestHeaders && requestData.requestHeaders["Content-Type"][0] == "application/json") {
$("#requestBody").html($("<pre/>").addClass("pre-scrollable").text(JSON.stringify(JSON.parse(atob(requestData.requestBody)), null, 4))[0].outerHTML);
$("#requestBody").html($("<pre/>").addClass("pre-scrollable w-100").text(JSON.stringify(JSON.parse(atob(requestData.requestBody)), null, 4))[0].outerHTML);
} else {
$("#requestBody").html($("<pre/>").addClass("pre-scrollable").text(atob(requestData.requestBody))[0].outerHTML);
$("#requestBody").html($("<pre/>").addClass("pre-scrollable w-100").text(atob(requestData.requestBody))[0].outerHTML);
}

$("#responseHeaders").html($("<pre/>").addClass("pre-scrollable").text(JSON.stringify(requestData.responseHeaders, null, 4))[0].outerHTML);
$("#responseHeaders").html($("<pre/>").addClass("pre-scrollable w-100").text(JSON.stringify(requestData.responseHeaders, null, 4))[0].outerHTML);

if ("Content-Type" in requestData.responseHeaders && requestData.responseHeaders["Content-Type"][0] == "application/json") {
$("#responseBody").html($("<pre/>").addClass("pre-scrollable").text(JSON.stringify(JSON.parse(atob(requestData.responseBody)), null, 4))[0].outerHTML);
$("#responseBody").html($("<pre/>").addClass("pre-scrollable w-100").text(JSON.stringify(JSON.parse(atob(requestData.responseBody)), null, 4))[0].outerHTML);
} else {
$("#responseBody").html($("<pre/>").addClass("pre-scrollable").text(atob(requestData.responseBody))[0].outerHTML);
$("#responseBody").html($("<pre/>").addClass("pre-scrollable w-100").text(atob(requestData.responseBody))[0].outerHTML);
}

$("#request-info-h2").text(`
Expand Down
6 changes: 5 additions & 1 deletion templates/header.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<!-- Bootstrap End -->

<!-- Knockout Start -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.1/knockout-latest.js"></script>
<!-- Knockout End -->

<style>
#pageContainer {
padding-top: 60px;
Expand Down Expand Up @@ -51,5 +55,5 @@
</ul>
</div>
</nav>
<div id="pageContainer" class="container">
<div id="pageContainer" class="container-fluid">
{{ end }}
Loading

0 comments on commit ed9f54f

Please sign in to comment.