3

(I originally created this question on StackOverflow but it was closed saying that it belongs in ServerFault)

I would like to use a Docker container on my Raspberry PI (machine A) to act as a VPN proxy for a specific website, and access that container from another machine (machine B) which is on the same local network. For that, I use a container with openvpn set up and an Nginx on top.

I use docker-compose to set up the container :

version: '2'
services:
 transmission:
  build:
    context: .
  cap_add:
    - NET_ADMIN
  devices:
    - "/dev/net/tun"
  restart: always
  ports:
    - "80:80"
    - "443:443"
  dns:
    - 8.8.8.8
    - 8.8.4.4

And the Nginx configuration in the container looks something like this :

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;

    server_name _ cool;

    location / {
        resolver 8.8.8.8;

        proxy_ssl_server_name on;
        proxy_http_version 1.1;
        proxy_pass https://coolwebsite.org$request_uri;
        proxy_pass_request_body on;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
    }
}

Then if I start the container and I add the following line in /etc/hosts on the PI host (machine A) :

127.0.0.1      cool

I can receive the contents of the target website by executing :

curl http://cool

Unfortunately, this doesn't work if I run the same curl command from machine B, even after adding the cool entry to its hosts file (although ping does work):

me@home:~$ telnet cool 80
Trying 192.168.1.35...
telnet: Unable to connect to remote host: Connection timed out
me@home:~$ curl http://cool
curl: (28) Failed to connect to cool port 80: Connection timed out
me@home:~$ ping cool
PING cool (192.168.1.35) 56(84) bytes of data.
64 bytes from cool (192.168.1.35): icmp_seq=1 ttl=63 time=7.10 ms

More diagnostics from machine A:

# netstat -tulnp | sort
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -
tcp6       0      0 :::22                   :::*                    LISTEN      -
tcp6       0      0 :::443                  :::*                    LISTEN      -
tcp6       0      0 :::8080                 :::*                    LISTEN      -
tcp6       0      0 :::80                   :::*                    LISTEN      -

Port 8080 listed above corresponds to a port binding from another container which can be accessed fine from machine B.

Also, if I stop my container and run sudo nc -l -p 80 to spin up a temporary web server, machine B can run curl http://cool successfully. That's why I think that something is wrong with the Docker setup, but what ? I saw some SO answers mentionning using network_mode: host but if my container shares the same IP as its host then it defeats my purpose of going through a VPN.

Let me know if I can provide more information.

7
  • did you try to listen on hostA with tcpdump your tun device for income connection from your hostB when using curl cool Sep 11, 2020 at 7:07
  • additionally, you can manually choose which device curl will use curl cool --interface <name> Sep 11, 2020 at 7:10
  • @MaratGainutdinov Thank you for the explanation. I do get results when listening using tcpdump port 80 : I get entries like 10:05:55.844574 IP desktop-88e11p0.home.50083 > raspberrypi.home.http: Flags [S], seq 1923779807, win 64240, options [mss 1460,nop,wscale 8,nop,nop,sackOK], length 0 but I don't know what to do with that information. I also applied the suggestion of prepending 0.0.0.0: at the beginning of the port binding in the docker-compose config, but it doesn't seem to change anything. Sep 12, 2020 at 9:10
  • @Bruno Pérel your netstat looks like your nginx doesn't listen on ipv4 for port 80. Did you ever consider this scenario? Your tcpdumo also shows, that your nginx isn't answering. Consider adding ipv6only=off. Sep 12, 2020 at 12:29
  • Also what happens if you change your hosts record on the nginx for cool to 192.168.1.35.Does it still work locally? Sep 12, 2020 at 12:44

1 Answer 1

1

Thought 1 Are you sure there are no host processes already camping on port 80?

Thought2 your docker-compose is missing any information about network mode - is it connecting to default bridge or something else?

Try adding a network section to the compose to create a new custom bridge. Note don't ever use the default bridge it is feature constrained. so in your case something like this:

version: '3'
services:
 transmission:
  build:
    context: .
  cap_add:
    - NET_ADMIN
  devices:
    - "/dev/net/tun"
  restart: always
  ports:
    - "80:80"
    - "443:443"
  dns:
    - 8.8.8.8
    - 8.8.4.4
  networks:
      - Transmission_Network

networks:
  - Transmission_Network

Thought 3 you nginx looks a little off, for example it should be server_name cool; not `server_name _ cool;

also this shouldn't be your default server. try this

server {
    listen 80;
    listen [::]:80;

    server_name cool;

    location / {
        resolver 8.8.8.8;
        proxy_set_header                        Host $http_host;
        proxy_set_header                        Upgrade $http_upgrade;
        proxy_set_header                        Connection "upgrade";
        proxy_http_version                      1.1;
        proxy_set_header                        X-Forwarded-Host $http_host;
        proxy_connect_timeout                   60s;
        proxy_send_timeout                      60s;
        proxy_read_timeout                      60s;
        proxy_http_version                      1.1;
        proxy_pass                              https://coolwebsite.org;
    }
}

note i included the common needed proxy set_headers as if you have one header set the location will not inherit from any set in http section.

1
  • I believe the final network section should contain a mapping, not a string: Transmission_Network: Feb 6, 2023 at 7:20

You must log in to answer this question.

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