Full Code of jnsgruk/wireguard-over-wss for AI

main 9d80ec6d003a cached
5 files
10.6 KB
3.2k tokens
1 requests
Download .txt
Repository: jnsgruk/wireguard-over-wss
Branch: main
Commit: 9d80ec6d003a
Files: 5
Total size: 10.6 KB

Directory structure:
gitextract_9snuufv1/

├── LICENSE
├── README.md
├── wss.conf
├── wss.wstunnel
└── wstunnel.sh

================================================
FILE CONTENTS
================================================

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2020 Jon Seager

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# Wireguard-over-Websockets Config

This project explains the steps to enable a Wireguard VPN connection to be tunnelled over a secure websockets connection for use cases where outbound VPN traffic may be blocked/filtered/monitored.

The following steps assume that there is already a Wireguard connection established that is to be modified for tunnelling over WSS.

## Server Configuration

No modifications need to be made to the Wireguard server configuration itself, but `wstunnel` needs to be installed and configured as a systemd unit.

1. Download the latest wstunnel [release](https://github.com/erebe/wstunnel/releases)
2. Copy the binary to `/usr/local/bin/wstunnel`
3. Allow the binary to listen on privileged ports:

```bash
version="$(curl -sL https://api.github.com/repos/erebe/wstunnel/releases | grep -m1 -Po 'tag_name": "\K[^"]+')"
curl -sL "https://github.com/erebe/wstunnel/releases/download/${version}/wstunnel_${version/v/}_linux_amd64.tar.gz" > wstunnel.tar.gz
tar xvzf wstunnel.tar.gz
sudo install -Dm 0755 wstunnel /usr/local/bin/wstunnel
sudo setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/wstunnel
```

4. Create the following service file at `/etc/systemd/system/wstunnel.service`:

```bash
[Unit]
Description=Tunnel WG UDP over websocket
After=network.target

[Service]
Type=simple
User=nobody
ExecStart=/usr/local/bin/wstunnel server wss://0.0.0.0:443 --restrict-to 127.0.0.1:51820
Restart=no

[Install]
WantedBy=multi-user.target
```

5. Start and enable the service:

```bash
$ sudo systemctl enable wstunnel
$ sudo systemctl start wstunnel
```

If relying solely on the software firewall installed on the droplet, ensure that inbound traffic to port 443 is permitted.

## Client Configuration

Ensure dependencies are installed (debian-based example):

```
apt update && apt install -y curl jq
```

1. Download the latest wstunnel [release](https://github.com/erebe/wstunnel/releases)
2. Copy the binary to `/usr/local/bin/wstunnel`
3. Copy existing config to `/etc/wireguard/wss.conf`
4. Install `wstunnel.sh` to `/etc/wireguard/wstunnel.sh` [(script)](./wstunnel.sh)
5. Create a connection specific config file at `/etc/wireguard/wss.wstunnel` [(example)](./wss.wstunnel):

```
REMOTE_HOST=some.server.com
REMOTE_PORT=51820
UPDATE_HOSTS='/etc/hosts'

# Change if using nginx with custom prefix for added security
# WS_PREFIX='E7m5vGDqryd55MMP'

# Change if running WSS on a non-standard port, i.e. 4443
# WSS_PORT=443

# Can change local port of the wstunnel, don't forget to change Peer.Endpoint
# LOCAL_PORT=${REMOTE_PORT}

# If using dnsmasq can supply other file than /etc/hosts
# UPDATE_HOSTS='/usr/local/etc/dnsmasq.d/hosts/tunnels'

# Will send -HUP to dnsmasq to reload hosts
# USING_DNSMASQ=1
```

Next we will modify the client config to configure routing and point at the correct endpoint for our websockets tunnel. (Or cheat, and look at the [example config](./wss.conf))

1. Ensure the `Endpoint` directive is pointing at `127.0.0.1:51820`
2. Add the following lines to the `[Interface]` section:

```
Table = off
PreUp = source /etc/wireguard/wstunnel.sh && pre_up %i
PostUp = source /etc/wireguard/wstunnel.sh && post_up %i
PostDown = source /etc/wireguard/wstunnel.sh && post_down %i
```

## Finish

The tunnelling should now be configured - ensure the server is running and `wstunnel` is started on the server and initiate a connection - you should then be able to see the tunnel established by running `wg`.

Ensure that all files under `/etc/wireguard` are owned by root:

```
$ chown -R root: /etc/wireguard
$ chmod 600 /etc/wireguard/*
```


================================================
FILE: wss.conf
================================================
[Interface]
PrivateKey = REPLACE_ME
Address = 10.0.0.3/24

Table = off
PreUp = source /etc/wireguard/wstunnel.sh && pre_up %i
PostUp = source /etc/wireguard/wstunnel.sh && post_up %i
PostDown = source /etc/wireguard/wstunnel.sh && post_down %i 

[Peer]
PublicKey = REPLACE_ME
Endpoint = 127.0.0.1:51820 # Note that this points to locahost!
AllowedIPs = 0.0.0.0/0 # Probably preferred if using tunnelling
PersistentKeepAlive = 25


================================================
FILE: wss.wstunnel
================================================
REMOTE_HOST=some.server.com
REMOTE_PORT=51820
UPDATE_HOSTS='/etc/hosts'

# Change if using CDN with custom IP or need use custom ip for domain (It's optional)
# if not set => auto get one of REMOTE_HOST ip
# REMOTE_IP=1.1.1.1

# Change if using nginx with custom prefix for added security
# WS_PREFIX='E7m5vGDqryd55MMP'

# Change if running WSS on a non-standard port, i.e. 4443
# export WSS_PORT=443

# Can change local port of the wstunnel, don't forget to change Peer.Endpoint
# LOCAL_PORT=${REMOTE_PORT}

# If using dnsmasq can supply other file than /etc/hosts
# UPDATE_HOSTS='/usr/local/etc/dnsmasq.d/hosts/tunnels'

# Will send -HUP to dnsmasq to reload hosts
# USING_DNSMASQ=1

================================================
FILE: wstunnel.sh
================================================
#!/usr/bin/env bash

#
# Original script downloaded from: https://github.com/Kirill888/notes/blob/wg-tunnel-update/wireguard/scripts/wstunnel.sh
# Modified by jnsgruk to use `ip route` for modern Linux distros
#
DEFAULT_HOSTS_FILE='/etc/hosts'

read_host_entry () {
    local host=$1
    local hfile=${2:-${DEFAULT_HOSTS_FILE}}
    awk -v host="$host" '{
     if( !($0~"^[ ]*#") && $2==host )
       print $1, ($0~"## wstunnel end-point")?"auto":"manual"
     }' "${hfile}"
}

add_host_entry () {
    local host=$1
    local ip=$2
    local hfile=${3:-${DEFAULT_HOSTS_FILE}}
    echo -e "${ip}\t${host}\t## wstunnel end-point" >> "${hfile}"
}

update_host_entry () {
    local host=$1
    local ip=$2
    local hfile=${3:-${DEFAULT_HOSTS_FILE}}
    local edited
    edited=$(awk -v host="$host" -v ip="$ip" '{
      if( !($0~"^[ ]*#") && $2==host && ($0~"## wstunnel end-point") )
        print ip "\t" host "\t" "## wstunnel end-point"
      else
        print $0
      }' "${hfile}")

    echo "${edited}" > "${hfile}"
}

delete_host_entry () {
    local host=$1
    local hfile=${2:-${DEFAULT_HOSTS_FILE}}
    local edited
    edited=$(awk -v host="$host" '{
      if( !($0~"^[ ]*#") && $2==host && ($0~"## wstunnel end-point") )
        ;
      else
        print $0
      }' "${hfile}")

    echo "${edited}" > "${hfile}"
}

maybe_update_host () {
    local host="$1"
    local current_ip="$2"
    local hfile=${3:-${DEFAULT_HOSTS_FILE}}
    local recorded_ip h_mode

    read -r recorded_ip h_mode < <(read_host_entry "${host}" "${hfile}") || true

    if [[ -z "${recorded_ip}" ]]; then
        echo "[#] Add new entry ${host} => <${current_ip}>"
        add_host_entry "${host}" "${current_ip}" "${hfile}"
    else
        if [[ "${recorded_ip}" == "${current_ip}" ]]; then
            echo "[#] Recorded address is already correct"
        else
            if [[ "${h_mode}" == "auto" ]]; then
                echo "[#] Updating ${recorded_ip} -> ${current_ip}"
                update_host_entry "${host}" "${current_ip}" "${hfile}"
            else
                echo "[#] Manual entry doesn't match current ip: ${recorded_ip} -> ${current_ip}"
                exit 2
            fi
        fi
    fi
}

launch_wstunnel () {
    local host=${REMOTE_HOST}
    local rport=${REMOTE_PORT:-51820}
    local wssport=${WSS_PORT:-443}
    local lport=${LOCAL_PORT:-${rport}}
    local prefix=${WS_PREFIX:-"wstunnel"}
    local user=${1:-"nobody"}
    local cmd

    cmd=$(command -v wstunnel)
    cmd="sudo -n -u ${user} -- $cmd"

    export NO_COLOR=true
    nohup $cmd &>/dev/null \
      client \
      --http-upgrade-path-prefix "${prefix}" \
      -L "udp://127.0.0.1:${lport}:127.0.0.1:${rport}" \
      "wss://${host}:${wssport}" &
    echo "$!"
}

pre_up () {
    local wg=$1
    local cfg="/etc/wireguard/${wg}.wstunnel"
    local remote remote_ip gw wstunnel_pid hosts_file _dnsmasq

    if [[ -f "${cfg}" ]]; then
        # shellcheck disable=SC1090
        source "${cfg}"
        remote=${REMOTE_HOST}
        remote_ip=${REMOTE_IP:-$(dig +short "${remote}" | head -n 1)}
        hosts_file=${UPDATE_HOSTS}
        _dnsmasq=${USING_DNSMASQ:-0}
    else
        echo "[#] Missing config file: ${cfg}"
        exit 1
    fi

    if [[ -z "${remote_ip}" ]]; then
        echo "[#] Can't resolve ${remote}"
        exit 1
    fi

    if [[ -f "${hosts_file}" ]]; then
        # Cache DNS in
        maybe_update_host "${remote}" "${remote_ip}" "${hosts_file}"

        [[ $_dnsmasq -eq 0 ]] || killall -HUP dnsmasq || true
    fi

    # Find out current route to ${remote_ip} and make it explicit
    gw=$(ip route get "${remote_ip}" | cut -d" " -f3)
    ip route add "${remote_ip}" via "${gw}" > /dev/null 2>&1 || true
    # Start wstunnel in the background
    wstunnel_pid=$(launch_wstunnel nobody)

    # save state
    mkdir -p /var/run/wireguard
    echo "${wstunnel_pid} ${remote} ${remote_ip} \"${hosts_file}\" ${_dnsmasq}" > "/var/run/wireguard/${wg}.wstunnel"
}

post_up () {
    local tun=$1
    ip route add 0.0.0.0/1 dev "${tun}" > /dev/null 2>&1
    ip route add ::0/1 dev "${tun}" > /dev/null 2>&1
    ip route add 128.0.0.0/1 dev "${tun}" > /dev/null 2>&1
    ip route add 8000::/1 dev "${tun}" > /dev/null 2>&1
}

post_down () {
    local tun=$1
    local state_file="/var/run/wireguard/${tun}.wstunnel"
    local wstunnel_pid remote remote_ip hosts_file _dnsmasq

    if [[ -f "${state_file}" ]]; then
        read -r wstunnel_pid remote remote_ip hosts_file _dnsmasq < "${state_file}"
        # unquote
        hosts_file=${hosts_file%\"}
        hosts_file=${hosts_file#\"}

        rm "${state_file}"
    else
        echo "[#] Missing state file: ${state_file}"
        exit 1
    fi

    kill -TERM "${wstunnel_pid}" > /dev/null 2>&1 || true

    if [[ -n "${remote_ip}" ]]; then
	    ip route delete "${remote_ip}" > /dev/null 2>&1 || true
    fi

    if [[ -f "${hosts_file}" ]]; then
        delete_host_entry "${remote}" "${hosts_file}"
        [[ $_dnsmasq -eq 0 ]] || killall -HUP dnsmasq || true
    fi
}
Download .txt
gitextract_9snuufv1/

├── LICENSE
├── README.md
├── wss.conf
├── wss.wstunnel
└── wstunnel.sh
Condensed preview — 5 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (12K chars).
[
  {
    "path": "LICENSE",
    "chars": 1067,
    "preview": "MIT License\n\nCopyright (c) 2020 Jon Seager\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
  },
  {
    "path": "README.md",
    "chars": 3596,
    "preview": "# Wireguard-over-Websockets Config\n\nThis project explains the steps to enable a Wireguard VPN connection to be tunnelled"
  },
  {
    "path": "wss.conf",
    "chars": 429,
    "preview": "[Interface]\nPrivateKey = REPLACE_ME\nAddress = 10.0.0.3/24\n\nTable = off\nPreUp = source /etc/wireguard/wstunnel.sh && pre_"
  },
  {
    "path": "wss.wstunnel",
    "chars": 684,
    "preview": "REMOTE_HOST=some.server.com\nREMOTE_PORT=51820\nUPDATE_HOSTS='/etc/hosts'\n\n# Change if using CDN with custom IP or need us"
  },
  {
    "path": "wstunnel.sh",
    "chars": 5049,
    "preview": "#!/usr/bin/env bash\n\n#\n# Original script downloaded from: https://github.com/Kirill888/notes/blob/wg-tunnel-update/wireg"
  }
]

About this extraction

This page contains the full source code of the jnsgruk/wireguard-over-wss GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 5 files (10.6 KB), approximately 3.2k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!