# WebTunnel bridge with Apache as reverse proxy

**URL:** https://forum.torproject.org/t/webtunnel-bridge-with-apache-as-reverse-proxy/13854
**Category:** Relay Operator
**Tags:** webtunnel
**Created:** [July 30, 2024, 6:26pm UTC](https://forum.torproject.org/t/webtunnel-bridge-with-apache-as-reverse-proxy/13854 "2024-07-30T18:26:38Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![anon68402605](https://forum.torproject.org/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@anon68402605](https://forum.torproject.org/u/anon68402605)
#### Post date: [July 30, 2024, 6:26pm UTC](https://forum.torproject.org/t/webtunnel-bridge-with-apache-as-reverse-proxy/13854/1 "2024-07-30T18:26:38Z")

</div>

Hi folks!

Unfortunately the [webtunnel bridge guide](https://community.torproject.org/relay/setup/webtunnel/) only seems to provide instructions on how to setup a webtunnel brige with nginx.  
Are there also instructions somewhere for doing this with Apache? I cannot find any.

So far I have adapted the nginx configuration to Apache syntax, but the bridge seems not to work.

I’m on Linux and have build the webtunnel server executable from source.  
After configuration and start of tor webtunnel instance verified that the webtunnel processes are running and listening on `127.0.0.1:15000`.

Threw `socat` in to check what Apache is passing to the webtunnel executable:  
`socat stdio tcp-listen:15000,fork`,  
pressed the ‘Connect’ button in Tor Browser and got the following output:

```auto
GET / HTTP/1.1
Host: example.com
User-Agent: Go-http-client/1.1
Accept-Encoding: 
X-Real-IP: 123.123.123.123
X-Forwarded-Proto: https
X-Forwarded-For: 123.123.123.123
X-Forwarded-Host: example.com
X-Forwarded-Server: example.com
Connection: Keep-Alive

```

Replaced the host name with `example.com` and the client IP address with `123.123.123.123` here. The rest is unchanged.

Also tried to send this output to the webtunnel process as follows:  
`printf "GET / HTTP/1.1\r\nHost: example.com\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: \r\nX-Real-IP: 123.123.123.123\r\nX-Forwarded-Proto: https\r\nX-Forwarded-For: 123.123.123.123\r\nX-Forwarded-Host: example.com\r\nX-Forwarded-Server: example.com\r\nConnection: Keep-Alive\r\n\r\n" | socat stdio tcp:127.0.0.1:15000`  
without any response…

Any ideas what’s wrong? When there is no guide for Apache, I will post the whole configuration here then.

---

<div class="post-metadata">

### Author: ![anon68402605](https://forum.torproject.org/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@anon68402605](https://forum.torproject.org/u/anon68402605)
#### Post date: [July 30, 2024, 11:30pm UTC](https://forum.torproject.org/t/webtunnel-bridge-with-apache-as-reverse-proxy/13854/2 "2024-07-30T23:30:32Z")

</div>

I found out there are two problems here. The first one is that the “magic path” doesn’t appear in the `GET` line which is required, but this is easy to solve.  
The second and the main problem is that Apache doesn’t allow to modify the `Connection` and `Upgrade` headers which is required for using of WebSockets. Nginx allows this modification.  
They must be set as follows:

```auto
Connection: Upgrade
Upgrade: websocket

```

But what you get from Apache (as you can see above) is

```auto
Connection: Keep-Alive

```

This requires some workaround. Bad decision of Apache devs…

I’ll be back…

---

<div class="post-metadata">

### Author: ![meskio](https://forum.torproject.org/user_avatar/forum.torproject.org/meskio/32/26_2.png) [@meskio](https://forum.torproject.org/u/meskio)
#### Post date: [July 31, 2024, 9:30am UTC](https://forum.torproject.org/t/webtunnel-bridge-with-apache-as-reverse-proxy/13854/3 "2024-07-31T09:30:38Z")

</div>

I don’t know much about apache, sorry. But if you find a solution it will be nice to extend the documentation including the apache configuration. This is the source of the documentation if you want to send us a merge request:

> **[content/relay/setup/webtunnel-bridge/contents.lr · main · The Tor Project /...](https://gitlab.torproject.org/tpo/web/community/-/blob/main/content/relay/setup/webtunnel-bridge/contents.lr?ref_type=heads)**
>
> Web repository of Community portal - https://community.torproject.org/

Good luck with the research.

---

<div class="post-metadata">

### Author: ![anon68402605](https://forum.torproject.org/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@anon68402605](https://forum.torproject.org/u/anon68402605)
#### Post date: [July 31, 2024, 10:56am UTC](https://forum.torproject.org/t/webtunnel-bridge-with-apache-as-reverse-proxy/13854/4 "2024-07-31T10:56:32Z")

</div>

Hi meskio!

I already have the solution and a working WebTunnel on Apache 🙂  
I also want to contribute it to the docs, but do not have an account on GitLab yet.  
But already requested and waiting for being unlocked.

---

<div class="post-metadata">

### Author: ![anon68402605](https://forum.torproject.org/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@anon68402605](https://forum.torproject.org/u/anon68402605)
#### Post date: [August 1, 2024, 8:35am UTC](https://forum.torproject.org/t/webtunnel-bridge-with-apache-as-reverse-proxy/13854/5 "2024-08-01T08:35:51Z")

</div>

Just for the case somebody will read this topic in the future and wants to know, how the HTTP headers to be sent to the webtunnel process have to look like (maybe for a setup of a WebTunnel bridge on another webserver/proxy):

```auto
GET /<RANDOM_STRING> HTTP/1.1
Host: <HOST_NAME>
User-Agent: Go-http-client/1.1
X-Real-IP: <CLIENT_IP_ADDRESS>
X-Forwarded-For: <CLIENT_IP_ADDRESS>
X-Forwarded-Proto: https
Connection: Upgrade
Upgrade: websocket

```

`User-Agent` is passed through from the browser.  
`<HOST_NAME>` has to be the host name of the host running the proxy.  
`<RANDOM_STRING>` is a placeholder for the random string generated by

```auto
echo $(cat /dev/urandom | tr -cd "qwertyuiopasdfghjklzxcvbnmMNBVCXZLKJHGFDSAQWERTUIOP0987654321"|head -c 24)

```

as mentioned in the [guide](https://community.torproject.org/relay/setup/webtunnel/).

`<CLIENT_IP_ADDRESS>` is a placeholder for the client (that’s where a browser is running) IP address.

I first thought that WebSocket usage is only required when some website uses them, but it turns out that the whole communication between Tor Browser and the webtunnel process happens through the WebSocket protocol. That’s why these two headers

```auto
Connection: Upgrade
Upgrade: websocket

```

have necessarily to be present on each connection.

If they are missing or have not the proper values, the upgrade to the Websocket protocol and that means any communication cannot happen. The webtunnel process simply doesn’t respond anything in this case.

I haven’t verified yet whether both headers `X-Real-IP` and `X-Forwarded-For` are required, because they both carry the same IP address and so one of them is redundant.  
I have taken them both over from the Nginx configuration example of the guide.

---

<div class="post-metadata">

### Author: ![anon68402605](https://forum.torproject.org/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@anon68402605](https://forum.torproject.org/u/anon68402605)
#### Post date: [August 28, 2024, 8:04pm UTC](https://forum.torproject.org/t/webtunnel-bridge-with-apache-as-reverse-proxy/13854/7 "2024-08-28T20:04:28Z")

</div>

Sorry, folks, I forgot to post the config.  
Was reminded via email notification caused by bakunin1848’s post.

Here is a working config:

```auto
<VirtualHost *:443>
    ServerName [[HOST_NAME]]

    Protocols http/1.1 h2

    SSLEngine on

    # Certificates generated via acme.sh
    SSLCertificateFile /root/.acme.sh/DOMAIN_ecc/fullchain.cer
    SSLCertificateKeyFile /root/.acme.sh/DOMAIN_ecc/DOMAIN.key

    SSLProtocol TLSv1.2 TLSv1.3
    SSLSessionCacheTimeout 900

    SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384

    ProxyPreserveHost On
    ProxyRequests off

    Header always set Strict-Transport-Security "max-age=63072000"

    <Location /[[SECRET_PATH]]>
        # This lets Apache set the "X-Forwarded-For", "X-Forwarded-Host" and
        # "X-Forwarded-Server" HTTP headers automatically if enabled (Default is 'On').
        # "X-Forwarded-For" is set manually below to avoid the other two
        # headers provided by this directive that we don't need.
        ProxyAddHeaders Off

        # Set Proxy headers
        RequestHeader unset Accept-Encoding
        RequestHeader set X-Real-IP "%{REMOTE_ADDR}s"
        RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}s"
        RequestHeader set X-Forwarded-Proto "%{REQUEST_SCHEME}s"
        Header set Front-End-Https on

        ProxyPass "ws://127.0.0.1:15000/%{REQUEST_URI}s"
        ProxyPassReverse "ws://127.0.0.1:15000%{REQUEST_URI}s"
    </Location>

    ErrorLog off
</VirtualHost>

```

Don’t forget to turn off the `CustomLog` (access log) also.  
If you don’t know how, use a search engine to find out.  
`CustomLog Off` doesn’t work.

You don’t need to use rewrite engine (@bakunin1848). This causes an unnecessary internal redirect in Apache. Use `ws://` prefix directly in `ProxyPass` and `ProxyPassReverse`.

There seems to be a bug in Apache’s `mod_proxy`.

In this line

```auto
ProxyPass "ws://127.0.0.1:15000/%{REQUEST_URI}s"

```

the slash after the port number has to be present, else `mod_proxy` complains, it cannot parse the URL. This will cause a double slash as result, but it doesn’t break anything.  
`ProxyPassReverse` does not have this bug.

Pls somebody add it to the webtunnel bridge documentation. I currently don’t have the time for it.

**Edit:**  
Caution!  
Even when `CustomLog` is not explicitly defined in a virtual host, Apache might still log accesses for such a virtual host, but to a file you maybe wouldn’t expect.

This file is on Debian/Ubuntu and derivatives (can differ on other OSes):

```auto
/var/log/apache2/other_vhosts_access.log

```

To disable logging to this file run the following command as root:

```auto
a2disconf other-vhosts-access-log

```

And then if Apache is already running:

```auto
systemctl reload apache2

```

---

<div class="post-metadata">

### Author: ![bakunin1848](https://forum.torproject.org/user_avatar/forum.torproject.org/bakunin1848/32/5591_2.png) [@bakunin1848](https://forum.torproject.org/u/bakunin1848)
#### Post date: [August 29, 2024, 1:48am UTC](https://forum.torproject.org/t/webtunnel-bridge-with-apache-as-reverse-proxy/13854/8 "2024-08-29T01:48:01Z")

</div>

The simpler and more optimal the better. I delete my configurations so that there are no misunderstandings and I leave your configuration.

Webtunnel Bridge ReverseProxy with Apache Config by @escurso

> **[SkynetCloud](https://paste.skynetcloud.site/?7fe22c84559e7666#8LbacZ6Dc4xEd96roQcLEvEfgVzF7T789fVAMVJY79L9)**
>
> Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.

---

<div class="post-metadata">

### Author: ![system](https://forum.torproject.org/uploads/default/original/2X/d/d3424bed34f4ec18b2e99178c2801ba6dfb655d6.png) [@system](https://forum.torproject.org/u/system)
#### Post date: [September 5, 2024, 10:56am UTC](https://forum.torproject.org/t/webtunnel-bridge-with-apache-as-reverse-proxy/13854/9 "2024-09-05T10:56:24Z")

</div>

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.
