├── .env.sample ├── Dockerfile ├── LICENSE ├── docker-compose.yml ├── identity.pub ├── index.html ├── readme.md └── start_tunnel.sh /.env.sample: -------------------------------------------------------------------------------- 1 | LETSENCRYPT_HOST= 2 | LETSENCRYPT_EMAIL= 3 | 4 | # Letsencrypt has a pretty strict rate limit of 5 per week, so if you 5 | # find yourself needing to debug things, uncomment this line: 6 | #LETSENCRYPT_TEST=true 7 | 8 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | #Both these ports are only exposed on the internal docker network 4 | 5 | # This is the port we're going to reverse tunnel 6 | EXPOSE 8080 7 | 8 | # This is the normal SSHd port (this gets mapped to 9 | # external port 2222 in the docker-compose.yml file) 10 | EXPOSE 22 11 | 12 | RUN apk --update add openssh \ 13 | && sed -i 's/#GatewayPorts no.*/GatewayPorts\ yes/' /etc/ssh/sshd_config \ 14 | && rm -rf /var/cache/apk/* 15 | 16 | RUN \ 17 | passwd -d root && \ 18 | adduser -D -s /bin/ash tunnel && \ 19 | passwd -u tunnel && \ 20 | chown -R tunnel:tunnel /home/tunnel && \ 21 | ssh-keygen -A 22 | 23 | VOLUME /home/tunnel/.ssh/authorized_keys 24 | 25 | CMD /usr/sbin/sshd -D 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | 5 | ssh-reverse-tunnel: 6 | restart: always 7 | image: ssh-reverse-tunnel 8 | build: ./ 9 | container_name: ssh-reverse-tunnel 10 | ports: 11 | - "2222:22" 12 | environment: 13 | - VIRTUAL_HOST=${LETSENCRYPT_HOST} 14 | - VIRTUAL_PORT=8080 # needs to be higher than 1024 for ssh to be able to reverse forward 15 | - LETSENCRYPT_HOST 16 | - LETSENCRYPT_EMAIL 17 | - LETSENCRYPT_TEST 18 | volumes: 19 | - ./identity.pub:/home/tunnel/.ssh/authorized_keys 20 | 21 | nginx-proxy: 22 | image: jwilder/nginx-proxy 23 | ports: 24 | - "80:80" 25 | - "443:443" 26 | volumes: 27 | - "/etc/nginx/vhost.d" 28 | - "/usr/share/nginx/html" 29 | - "/var/run/docker.sock:/tmp/docker.sock:ro" 30 | - "/etc/nginx/certs" 31 | 32 | letsencrypt-nginx-proxy-companion: 33 | image: jrcs/letsencrypt-nginx-proxy-companion 34 | volumes: 35 | - "/var/run/docker.sock:/var/run/docker.sock:ro" 36 | volumes_from: 37 | - "nginx-proxy" -------------------------------------------------------------------------------- /identity.pub: -------------------------------------------------------------------------------- 1 | Replace this file with your own public SSH key. -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Testing... 5 | 6 | 7 |

It works!

8 | 9 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | ## To run this example you will need: 3 | 4 | A server running docker with a DNS name pointing to it. (If you don't already have one setup, using [docker-machine]( https://docs.docker.com/machine/get-started-cloud/#examples) can make it easier to setup and deploy to your server.) Your server will need ports 80, 443, and 2222 open to the public. 5 | 6 | The following instructions assume you're using docker-machine. This will definitely work without it, but you'll have to do a bit more manual copying of files. And you'll probably want to clone the repo on your server rather than locally. 7 | 8 | - Clone this repo 9 | - Replace the content of `identity.pub` with your own SSH public key. 10 | - Adjust file permissions: 11 | ``` 12 | chmod 644 identity.pub 13 | ``` 14 | - Rename the `.env.sample` file to `.env`and int it replace `replace.this.example.com` with the DNS name of your server and `replace.with.your@email.com` with your email. Letsencrypt has a pretty strict rate limit of 5 per week, so if you find yourself needing to debug things, uncomment the line `LETSENCRYPT_TEST=true`. The test certs will by considered unsecure by browsers but it should let you test the basic functionality without hitting the rate limit. 15 | - Then to launch the docker containers: 16 | ``` 17 | eval $(docker-machine env your-server-name) 18 | docker-compose up 19 | ``` 20 | - Now on your local machine you can test the tunnel with something like: 21 | ``` 22 | python -m SimpleHTTPServer 3000 . 23 | ./start_tunnel.sh 3000 whatever.your.domain.is 24 | ``` 25 | - Open browser to whatever.your.domain.is and you should see an "It works!" -------------------------------------------------------------------------------- /start_tunnel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | [ $# -lt 2 ] && { echo "Usage: $0 port_of_local_service hostname" ; exit 1; } 3 | ssh -N -o ExitOnForwardFailure=yes -o ServerAliveInterval=300 -o ConnectTimeout=5 -g -R 8080:localhost:$1 -p 2222 tunnel@$2 --------------------------------------------------------------------------------