I'm facing a problem - I would like to connect many embedded devices with OpenWRT to my Wireguard server, but all the ports except 80, 443 and some others are blocked. Moreover only TCP is allowed in network.

It seems like I need to tunnel WireGuard which is UDP, into TCP. On my server I would like to use SSHL (port sharing) service to run HTTPS server and tunnel for WireGuard simultaneously on 443 (or other allowed by firewall) port. I would like to have multiuser capable tunnel, so I suspect quick socat hacks will not work for more clients.

  • I tried wireguard-proxy, it works perfectly with port sharing over SSLH but it is written in Rust, and I cant deploy it on OpenWRT (I tried, and got compiling errors). -I tested also udp2raw, and it also works well on dedicated port, but I can't connect to it when using SSLH port multiplexer.

I'm looking for some tunneling software written in C/C++ that I can cross-compile in OpenWRT build system, and use with my modded network devices.

  • rust works beautifully on any Linux target, so you need to fix these compilation errors. It shouldn't be too hard – you should be able to just cross-compile statically. Commented Mar 26, 2023 at 15:12
  • Did you ever try my answer? Did something get wrong?
    – A.B
    Commented Apr 22, 2023 at 18:48
  • Thank! yes! i tried, and it worked! but transfer speed was horrible. So I used udp-over-tcp , and then even found better software called chisel, because it can tunnel multiple services with one service
    – Sink
    Commented Apr 23, 2023 at 20:23
  • I see. But if you found an other solution that works for you, you should post it as an answer and (after 48h) mark it as the solution. Else your question will still come back as a not solved question.
    – A.B
    Commented Apr 23, 2023 at 20:39

1 Answer 1


You can use socat as tunneling software.

Here would be a typical setup (done interactively) with WireGuard listening on port 51820. You will still have to do adequate integration in startup services.

OpenWRT (but actually tested on an other Linux)

  • Enable the Wireguard interface as usual

    ... except for the MTU: see the description in the Notes below. Let's use an MTU of 1420-64=1356. Example (should actually be done in wg0.conf when using wg-quick):

    ip link set wg0 mtu 1356
  • terminal1:

    sslh -n --listen \
        --tls \
        --anyprot \

    sslh won't recognize WireGuard's protocol, so it will go to the --anyprot destination.

  • terminal2:

    socat -T 120 \
        tcp4-listen:51820,bind=,reuseaddr,nodelay,fork \

    As socat suggests for an other case:

    Note: If you intend to transfer packets between two Socat "wire sides" you need a protocol that keeps packet boundaries, e.g.UDP; TCP might work with option nodelay.

    While sslh doesn't specifically use nodelay, both socat will, hopefully helping for this part.

    The -T 120 is the delay of inactivity before forked socats end. Useful if the client roams and loses connection. Should be set to a value higher than expected client's WireGuard persistent keepalive. Anyway, won't help much in case of non-TLS DDoS: there will be several forked socats and this can only help a DoS (WireGuard itself will ignore such traffic).


  • terminal1:

    socat -T 120 \
        udp4-listen:51821,bind=,fork \

    Actually if the client roams, this socat command might have to be restarted because its TCP part might take time to fail properly.

  • Wireguard interface

    As before, lower the MTU. On Linux that would be again:

    ip link set wg0 mtu 1356

    And change the peer endpoint to switch to the tunnel entrance which is now on the local system (again, should be done in client's wg0.conf):

    wg set wg0 peer XXXXXXXXX= endpoint

Now as soon as the client sends any packet within the tunnel and has authenticated, Server's WireGuard will update its client endpoint (to from the local socat) and can reply. This makes this full duplex communication:

client ⟺ WG ⟺ UDP ⟺ socat ⟺ TCP over Internet 
server ⟺ WG ⟺ UDP ⟺ socat ⟺ TCP ⟺ sslh


  • MTU considerations

    In addition to the usual 80 bytes overhead (1500-80=1420) WireGuard reserves, one has to add the TCP overhead. This is to avoid that the outer tunnel layer: socat+sslh which are not aware of the underlying protocol get a too big payload split in two TCP packets: this might destroy at least the 2nd encapsulated UDP payload, causing retransmissions.

    This overhead is actually dynamic. For IPv4, It's at least 20 for IP plus 20 for TCP. Then any modern TCP connection uses 2+8+2=12 bytes for timestamp, and will have to use a random number of SACKs when packets get lost. Let's allow for one (2+2*4+2=12): 20+20+12+12=64. The exact value doesn't really matter (are there actually two TCP NOPs between these two TCP options to align each one? I don't know). So in the end I chose that the WireGuard MTU will be 1420-64=1356.

    Some tests done over an actual physical LAN using ping -M do -s $MTU-28 -f 10.x.x.x showed here that keeping MTU=1420 on the interfaces would lose ~ 40% packets, and that MTU=1356 wouldn't lose any, even if higher MTUs also appear to be adequate.

  • case of a restriction on port 443 also requiring SSL

    If the firewall limiting to port 443 expects only SSL traffic on this port, then things would get more complicated. One should replace sslh with haproxy or nginx (both appearing to be packaged on OpenWRT, I don't know if the required feature was made available) and use their TLS pass-through feature to route a TLS connection depending on the received ClientHello's SNI. The two socats would then replace tcp-listen/tcp with openssl-listen/openssl to communicate, but I'm not sure how MTU would be affected in this case.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .