├── .gitignore ├── sockd.sh ├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── build_publish.yml │ └── build_only.yml ├── images └── logo.png ├── sockd.conf ├── Dockerfile ├── LICENSE ├── docker-compose.yml ├── startup.sh └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode -------------------------------------------------------------------------------- /sockd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | sockd -D -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: ilteoood 2 | -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ilteoood/docker-surfshark/HEAD/images/logo.png -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: docker 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "04:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /sockd.conf: -------------------------------------------------------------------------------- 1 | logoutput: stdout 2 | 3 | internal: eth0 port = 1080 4 | external: tun0 5 | 6 | user.unprivileged: sockd 7 | 8 | socksmethod: none 9 | clientmethod: none 10 | 11 | client pass { 12 | from: 0.0.0.0/0 to: 0.0.0.0/0 13 | log: error 14 | } 15 | 16 | socks pass { 17 | from: 0.0.0.0/0 to: 0.0.0.0/0 18 | } -------------------------------------------------------------------------------- /.github/workflows/build_publish.yml: -------------------------------------------------------------------------------- 1 | name: Build and publish image 2 | on: 3 | release: 4 | types: [published] 5 | schedule: 6 | - cron: '0 3 * * 1' 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | name: Build and publish image job 12 | steps: 13 | - name: Checkout master 14 | uses: actions/checkout@master 15 | - name: Build and publish image 16 | uses: ilteoood/docker_buildx@master 17 | with: 18 | tag: latest,1.8.1 19 | imageName: ilteoood/docker-surfshark 20 | platform: linux/amd64,linux/arm64,linux/ppc64le,linux/s390x,linux/386,linux/arm/v7,linux/arm/v6 21 | publish: true 22 | dockerUser: ilteoood 23 | dockerPassword: ${{ secrets.DOCKER_HUB_PASSWORD }} 24 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | LABEL maintainer.name="Matteo Pietro Dazzi" \ 3 | maintainer.email="matteopietro.dazzi@gmail.com" \ 4 | version="1.8.1" \ 5 | description="OpenVPN client and socks5 server configured for SurfShark VPN" 6 | WORKDIR /vpn 7 | ENV SURFSHARK_USER= 8 | ENV SURFSHARK_PASSWORD= 9 | ENV SURFSHARK_COUNTRY= 10 | ENV SURFSHARK_CITY= 11 | ENV SURFSHARK_CONFIGS_ENDPOINT=https://my.surfshark.com/vpn/api/v1/server/configurations 12 | ENV OPENVPN_OPTS= 13 | ENV CONNECTION_TYPE=tcp 14 | ENV LAN_NETWORK= 15 | ENV CREATE_TUN_DEVICE= 16 | ENV ENABLE_MASQUERADE= 17 | ENV ENABLE_SOCKS_SERVER= 18 | ENV OVPN_CONFIGS= 19 | ENV ENABLE_KILL_SWITCH=true 20 | HEALTHCHECK --interval=60s --timeout=10s --start-period=30s CMD curl -s https://api.surfshark.com/v1/server/user | grep '"secured":true' 21 | COPY startup.sh . 22 | COPY sockd.conf /etc/ 23 | COPY sockd.sh . 24 | RUN apk add --update --no-cache openvpn wget unzip coreutils curl ufw dante-server \ 25 | && chmod +x ./startup.sh \ 26 | && chmod +x ./sockd.sh 27 | ENTRYPOINT [ "./startup.sh" ] 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Matteo Pietro Dazzi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/build_only.yml: -------------------------------------------------------------------------------- 1 | name: Build only image 2 | on: 3 | push: 4 | branches: 5 | - master 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | name: Build only image job 11 | steps: 12 | - name: Checkout master 13 | uses: actions/checkout@master 14 | - name: Build image 15 | uses: ilteoood/docker_buildx@master 16 | with: 17 | tag: latest,1.8.1 18 | platform: linux/amd64,linux/arm64,linux/ppc64le,linux/s390x,linux/386,linux/arm/v7,linux/arm/v6 19 | imageName: ilteoood/docker-surfshark 20 | - name: Scan image 21 | uses: anchore/scan-action@v2 22 | with: 23 | image: "ilteoood/docker-surfshark:latest" 24 | fail-build: true 25 | acs-report-enable: true 26 | severity-cutoff: critical 27 | - name: Anchore inline scan JSON results 28 | run: for j in `ls ./anchore-reports/*.json`; do echo "---- ${j} ----"; cat ${j}; echo; done 29 | - name: Inspect action SARIF report 30 | run: cat ${{ steps.scan.outputs.sarif }} 31 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | services: 4 | surfshark: 5 | image: ilteoood/docker-surfshark 6 | container_name: surfshark 7 | environment: 8 | - SURFSHARK_USER=YOUR_SURFSHARK_USER 9 | - SURFSHARK_PASSWORD=YOUR_SURFSHARK_PASSWORD 10 | - SURFSHARK_COUNTRY=it 11 | - SURFSHARK_CITY=mil 12 | - CONNECTION_TYPE=udp 13 | - LAN_NETWORK=192.168.0.0/24 #Optional - Used to access attached containers web ui 14 | cap_add: 15 | - NET_ADMIN 16 | devices: 17 | - /dev/net/tun 18 | ports: 19 | - 9091:9091 #We open here the port for transmission, as this container will be the access point for the others 20 | restart: unless-stopped 21 | dns: 22 | - 1.1.1.1 23 | service_test: 24 | image: byrnedo/alpine-curl 25 | container_name: alpine 26 | command: -L 'https://ipinfo.io' 27 | depends_on: 28 | - surfshark 29 | network_mode: service:surfshark 30 | restart: always 31 | transmission: 32 | image: linuxserver/transmission 33 | container_name: transmission 34 | environment: 35 | - PUID=1000 36 | - PGID=1000 37 | - TZ=Europe/Rome 38 | #ports: 39 | #- 9091:9091 needed to access transmission's GUI 40 | network_mode: service:surfshark 41 | restart: unless-stopped 42 | -------------------------------------------------------------------------------- /startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | rm -rf ovpn_configs* 3 | if [ -z "${OVPN_CONFIGS}" ]; then 4 | wget -O ovpn_configs.zip ${SURFSHARK_CONFIGS_ENDPOINT} 5 | OVPN_CONFIGS=ovpn_configs.zip 6 | fi 7 | unzip "${OVPN_CONFIGS}" -d ovpn_configs 8 | cd ovpn_configs 9 | VPN_FILE=$(ls *"${SURFSHARK_COUNTRY}"-* | grep "${SURFSHARK_CITY}" | grep "${CONNECTION_TYPE}" | shuf | head -n 1) 10 | echo Chose: ${VPN_FILE} 11 | printf "${SURFSHARK_USER}\n${SURFSHARK_PASSWORD}" > vpn-auth.txt 12 | 13 | if [ -n ${LAN_NETWORK} ] 14 | then 15 | DEFAULT_GATEWAY=$(ip -4 route list 0/0 | cut -d ' ' -f 3) 16 | 17 | splitSubnets=$(echo ${LAN_NETWORK} | tr "," "\n") 18 | 19 | for subnet in $splitSubnets 20 | do 21 | ip route add "$subnet" via "${DEFAULT_GATEWAY}" dev eth0 22 | echo Adding ip route add "$subnet" via "${DEFAULT_GATEWAY}" dev eth0 for attached container web ui access 23 | done 24 | 25 | echo Do not forget to expose the ports for attached container web ui access 26 | fi 27 | 28 | if [ "${CREATE_TUN_DEVICE}" = "true" ]; then 29 | echo "Creating TUN device /dev/net/tun" 30 | mkdir -p /dev/net 31 | mknod /dev/net/tun c 10 200 32 | chmod 0666 /dev/net/tun 33 | fi 34 | 35 | # Enable NAT w MASQUERADE mode 36 | if [ "${ENABLE_MASQUERADE}" = "true" ]; then 37 | echo "Enabling IP MASQUERADE using IP Tables" 38 | iptables -t nat -A POSTROUTING -o tun+ -j MASQUERADE 39 | fi 40 | 41 | 42 | OPTIONAL_SOCKS_SCRIPT="" 43 | # Enable NAT w MASQUERADE mode 44 | if [ "${ENABLE_SOCKS_SERVER}" = "true" ]; then 45 | echo "Enable SOCKS Server for the VPN" 46 | OPTIONAL_SOCKS_SCRIPT="--up /vpn/sockd.sh" 47 | fi 48 | 49 | openvpn --config $VPN_FILE --auth-user-pass vpn-auth.txt --mute-replay-warnings $OPENVPN_OPTS --script-security 2 ${OPTIONAL_SOCKS_SCRIPT} 50 | 51 | if [ "${ENABLE_KILL_SWITCH}" = "true" ]; then 52 | ufw reset 53 | ufw default deny incoming 54 | ufw default deny outgoing 55 | ufw allow out on tun0 from any to any 56 | ufw enable 57 | fi 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker-surfshark 2 | 3 | Docker container with OpenVPN client preconfigured for SurfShark 4 | 5 | [![](https://images.microbadger.com/badges/version/ilteoood/docker-surfshark.svg)](https://microbadger.com/images/ilteoood/docker-surfshark "Get your own version badge on microbadger.com") 6 | [![](https://images.microbadger.com/badges/image/ilteoood/docker-surfshark.svg)](https://microbadger.com/images/ilteoood/docker-surfshark "Get your own image badge on microbadger.com") 7 | ![Build only image](https://github.com/ilteoood/docker-surfshark/workflows/Build%20only%20image/badge.svg?branch=master) 8 | 9 | ------------------------------------------------ 10 |

11 | logo 12 |

13 | 14 | This is a [multi-arch](https://medium.com/gft-engineering/docker-why-multi-arch-images-matters-927397a5be2e) image, updated automatically thanks to [GitHub Actions](https://github.com/features/actions). 15 | 16 | Its purpose is to provide the [SurfShark VPN](https://surfshark.com/) to all your containers. 17 | 18 | The link is established using the [OpenVPN](https://openvpn.net/) client. 19 | 20 | ## Configuration 21 | 22 | The container is configurable using different environment variables: 23 | 24 | | Name | Mandatory | Description | 25 | |------|-----------|-------------| 26 | |SURFSHARK_USER|Yes|Username provided by SurfShark| 27 | |SURFSHARK_PASSWORD|Yes|Password provided by SurfShark| 28 | |SURFSHARK_COUNTRY|No|The country, supported by SurfShark, in which you want to connect| 29 | |SURFSHARK_CITY|No|The city of the country in which you want to connect| 30 | |SURFSHARK_CONFIGS_ENDPOINT|No|The endpoint to be used to read Surfshark's configuration zip| 31 | |OPENVPN_OPTS|No|Any additional options for OpenVPN| 32 | |CONNECTION_TYPE|No|The connection type that you want to use: tcp, udp| 33 | |LAN_NETWORK|No|Lan network used to access the web ui of attached containers. Can be comma seperated for multiple subnets Comment out or leave blank: example 192.168.0.0/24| 34 | |CREATE_TUN_DEVICE|No|Creates the TUN device, useful for NAS users| 35 | |ENABLE_MASQUERADE|No|Masquerade NAT allows you to translate multiple IP addresses to another single IP address.| 36 | |ENABLE_SOCKS_SERVER|No|Control whether the SOCKS server for the VPN is run or not (default: do not run)| 37 | |OVPN_CONFIGS|No|Manually provide the path used to read the "Surfshark_Config.zip" file (contains Surshark's OpenVPN configuration files) 38 | |ENABLE_KILL_SWITCH|No|Enable the kill-switch functionality 39 | 40 | `SURFSHARK_USER` and `SURFSHARK_PASSWORD` are provided at [this page](https://my.surfshark.com/vpn/manual-setup/main/openvpn). 41 | 42 |

43 | SurfShark credentials 44 |

45 | 46 | ## Execution 47 | 48 | You can run this image using [Docker compose](https://docs.docker.com/compose/) and the [sample file](./docker-compose.yml) provided. 49 | **Remember: if you want to use the web gui of a container, you must open its ports on `docker-surfshark` as described below.** 50 | 51 | ``` 52 | version: "2" 53 | 54 | services: 55 | surfshark: 56 | image: ilteoood/docker-surfshark 57 | container_name: surfshark 58 | environment: 59 | - SURFSHARK_USER=YOUR_SURFSHARK_USER 60 | - SURFSHARK_PASSWORD=YOUR_SURFSHARK_PASSWORD 61 | - SURFSHARK_COUNTRY=it 62 | - SURFSHARK_CITY=mil 63 | - CONNECTION_TYPE=udp 64 | - LAN_NETWORK= 65 | cap_add: 66 | - NET_ADMIN 67 | devices: 68 | - /dev/net/tun 69 | ports: 70 | - 1080:1080 #if you want to use the socks5 server 71 | - 9091:9091 #we open here the port for transmission, as this container will be the access point for the others 72 | restart: unless-stopped 73 | dns: 74 | - 1.1.1.1 75 | service_test: 76 | image: byrnedo/alpine-curl 77 | container_name: alpine 78 | command: -L 'https://ipinfo.io' 79 | depends_on: 80 | - surfshark 81 | network_mode: service:surfshark 82 | restart: always 83 | transmission: 84 | image: linuxserver/transmission 85 | container_name: transmission 86 | environment: 87 | - PUID=1000 88 | - PGID=1000 89 | - TZ=Europe/Rome 90 | #ports: 91 | #- 9091:9091 needed to access transmission's GUI 92 | network_mode: service:surfshark 93 | restart: unless-stopped 94 | ``` 95 | 96 | Or you can use the standard `docker run` command. 97 | 98 | ```sh 99 | sudo docker run -it --cap-add=NET_ADMIN --device /dev/net/tun --name CONTAINER_NAME -e SURFSHARK_USER=YOUR_SURFSHARK_USER -e SURFSHARK_PASSWORD=YOUR_SURFSHARK_PASSWORD ilteoood/docker-surfshark 100 | ``` 101 | 102 | If you want to attach a container to the VPN, you can simply run: 103 | 104 | ```sh 105 | sudo docker run -it --net=container:CONTAINER_NAME alpine /bin/sh 106 | ``` 107 | 108 | If you want access to an attached container's web ui you will also need to expose those ports. 109 | The attached container must not be started until this container is up and fully running. 110 | 111 | If you face network connection problems, I suggest you to set a specific DNS server for each container. 112 | 113 | Alternatively, if your software supports it, you can use the socks5 server embedded in this container. It will redirect your traffic through the Surfshark's VPN. 114 | 115 | ## Provide OpenVPN Configs Manually 116 | 117 | Sometimes the startup script fails to download OpenVPN configs file from Surfshark's website, possibly due to the DDoS protection on it. 118 | 119 | 120 | To avoid it, you can provide your own `Surfshark_Config.zip` file, downloading it from [here](https://my.surfshark.com/vpn/api/v1/server/configurations). 121 | 122 | Then, you **must** make the `zip` available inside the container, using a [bind mount](https://docs.docker.com/storage/bind-mounts/) or a [volume](https://docs.docker.com/storage/volumes/). 123 | 124 | Finally, you **must** set the `OVPN_CONFIGS` environment variable. 125 | 126 | ## Do you like my work? 127 |

128 | 129 | patreon 130 | 131 | 132 | or 133 | 134 | buy-me-a-coffee 135 | 136 | 137 |

138 | --------------------------------------------------------------------------------