Closed ghostserverd closed 4 years ago
Thanks for the kind words and your detailed explanation! This is also a good learning for me as I have not used the network_mode: service before and I like what you are doing here.
What you need is a conditional forwarder, which requires a local dnsserver in the same container (or probably better another docker service) to serve the DNS requests and point them to the right place (dnsmasq should work as you mentioned with some tweaks).
So here is my (untested) idea: First configure all your services to use a local domain name (like 'local') via the aliases. e.g.:
networks:
default:
aliases:
- watismyip_clear.local
Then set up a dnsmasq container (could also share the network with the wireguard service) with conf like so:
#dont use hosts nameservers
no-resolv
# listen specifically on 127.0.0.1
listen-address=127.0.0.1
# send queries for local domain to docker
server=/local/127.0.0.11
# send queries for all else to upstream dns
server=9.9.9.9
Then in your wg0.conf, DNS=127.0.0.1
, which will set your resolv.conf to
# Generated by resolvconf
nameserver 127.0.0.1
So what will happen is that all the DNS queries will go to your dnsmasq server. The dnsmasq server will in turn forward queries for the .local domain names to docker for resolution, or do the default upstream for everything else.
Definitely adds some complexity that is not ideal but I think it will work. Unfortunately it does not look like there is a way to do conditional nameservers in resolv.conf directly or it would make this a lot simpler.
Ah that's a good tip about setting a local TLD.
I set up dnsmasq
in the wireguard
container, and set the alias with the .local
TLD. I can
curl watismyip_clear.local:5555
from within the watismyip_vpn
container which is super neat!
Now I just need to do some digging to see if dnsmasq
can support an address without a TLD (might not be possible, but it would be nice to not have to alias each container).
I did have to disable the MASQUERADE
rule in order for it to work. With the rule in place, even when I manually specified the DNS address (e.g. dig @127.0.0.11 watismyip_vpn.local
) the request times out.
What exactly is that MASQUERADE
rule for? Is it just masking the docker subdomain in outgoing packets? Or is there more to it than that? Is it safe to disable?
Thanks for your help!
The MASQUERADE rule is really meant for the "server" side so it is ok for you to disable in this case. It does a NAT for all outbound traffic to the Internet (out eth0). Technically I'm not sure why it would have an effect on the local DNS lookups to 127.0.0.11, but docker does some interesting NAT stuff of its own for that built-in DNS so there may be some interference there.
All right. I've made some progress.
I updated my fork of this repo to do the following:
/etc/dnsmasq.conf
with that as the final fallback DNS address./etc/hosts
with any service in the network (this is really just for backwards comptability)LOCAL_TLD
is set (e.g. to local
) write /etc/dnsmasq.conf
to use 127.0.0.11
for that TLD. Also, write /etc/resolv.conf
to search $LOCAL_TLD
so that containers can access the addresses of the services without having to know to append .local
to match the rule in /etc/dnsmasq.conf
. This will require aliases with the TLD in each of the containers that need to be accessible from within the wireguard
network.SERVICE_NAMES
is set (a list of services to make available from within the wireguard
network), write each service name individually to /etc/dnsmasq.conf
to force 127.0.0.11
as the DNS server for each service address. This is nice because you don't have to write an alias for each service to make available, but you do need to list out all of the services anyway.The last three are really mutually exclusive. Only one of the mechanisms should be used. Of the last two, I'm not really sure which one I prefer, but they're both better than mounting docker.sock
in my opinion.
Thanks for your help on this! I'm going to resolve this issue now since I think I've come up with acceptable mechanisms for making docker DNS resolve from within containers using the wireguard
network without having to mount docker.sock
.
Hey there. Firstly, thanks for building this container. It's been very informative as I build out VPN connected services.
I have an issue to submit regarding DNS resolution for other docker services in the same network.
Some Background
As you likely know, when multiple containers are running in the same docker network, they are accessible via
<container_name>:<port>
as opposed to having to connect to each container by its IP address. This is accomplished by docker's internal DNS server which is accessible from within each container at address127.0.0.11
.I believe that because
wg-quick
rewrites/etc/resolv.conf
, thiswireguard
container breaks docker DNS resolution from within the container, and from within any container that uses thiswireguard
container as a network service.I have an example docker-compose that shows this in action:
garrettsparks/watismyip
is just a small container I found which queries some external services for the current public IP address (with a fallback to the private IP if the container cannot contact any of the external services) of the container.There are three services along with the
wireguard
service.watismyip_vpn
uses thewireguard
container as its network. Thenwatismyip_clear
andwatismyip_clear_2
are just normal containers not using thewireguard
network.The goal is that
watismyip_vpn
can callwatismyip_clear:5555
,watismyip_clear
can callwatismyip_vpn:4444
andwatismyip_clear
can callwatismyip_clear_2:6666
.The last two scenarios work as expected. The two
clear
containers can talk to each other just fine using their service namesand the
clear
containers can talk to thewatismyip_vpn
container via its service name because of the network alias set up in thewireguard
container.However, when I attempt to call
watismyip_clear:5555
from within thewatismyip_vpn
container, I get a DNS resolution failureI believe that the root cause of this is that
/etc/resolv.conf
is re-written bywg-quick
. For example, in the non-vpn containers, this is/etc/resolv.conf
vs in the
watismyip_vpn
containerwhich makes perfect sense because the wireguard configuration specifies a different DNS address to force DNS to the VPN's DNS resolver which avoids leaking your DNS queries.
The Question
My kludgy workaround is to mount
docker.sock
, do adocker network inspect
on the docker network, and then write/etc/hosts
with each of the service's docker network IP address, but I'd prefer to find a way to do this without having to mountdocker.sock
, and with this workaround, if the service IPs ever change, thewireguard
container would have to be restarted to pick up the new IP address.I believe this should be possible with a
dnsmasq
config that's something likeand updating
/etc/resolv.conf
to bebut that didn't work, and I'm not a
dnsmasq
expert unfortunately.Do you know of a way to retain support for docker DNS resolution while also using the VPN's DNS resolution for public DNS queries with this
wireguard
container?Sorry for the wall of info and thanks again!