Skip to content

Instantly share code, notes, and snippets.

@HarvsG
Last active October 22, 2023 12:29
Show Gist options
  • Save HarvsG/008700c8d187b072cca335b9a85ad34d to your computer and use it in GitHub Desktop.
Save HarvsG/008700c8d187b072cca335b9a85ad34d to your computer and use it in GitHub Desktop.
How I set up and always on wigaurd PiHole VPN and DNS

Inspired from this guide

Signing up for Oracle Free Tier

Navigate to https://myservices.us.oraclecloud.com/mycloud/signup and input your information and click next.

💡 If you don’t want to use your card number for verification you can signup for free at http://bit.ly/privacysignup and get $5 for free at the same time.

image

Finish the signup process (no more than 5 minutes) and you’re good to go.

Creating our Virtual Machine Once we’re all logged in, on our dashboard, click “Create VM Instance”.

image

First we input a name for our instance and second select the compartment (the default is fine). Then we need to click “Change Image”. We need to select “ Canonical Ubuntu 18.04 “.

image

Make sure you have the “Always Free Eligible” VM type selected

![image][https://miro.medium.com/max/678/0*drNm5YsMzOfLr5LD]

Next we need to generate our SSH Keys. And finally we click paste and paste the public key from your device or password manager.

After creating the virtual machine scroll down and click “VNIC” on the left in the side bar under Resources and edit your VNIC.

image

Check “Skip source/destination check”

image

Save changes.

When viewing your instance in the control panel, under “Primary VNIC” click “Public Subnet”

image

Then click “Default Security List for vnc-0000000” Click “Add Ingress Rules” Rule 1: Source Type: CIDR Souce CIDR: 0.0.0.0/0 IP Protocol: UDP Destination Port: 51820 Description: WireGuard UDP Click the blue “Add Ingress Rules” button.

SSH into the device

$ ssh ubuntu@the.ip.of.the.instance

Then install the PiVPN

$ curl -L https://install.pivpn.io | bash

If it asks the DNS location choose the options that says the DNS is local pi or similar

Point a DNS provider such as digital ocean at the static IP of the instance

Then make sure to include that DNS entry as the location of the server

sudo nano /etc/wireguard/wg0.conf

Under [Interfaces] add

PostUp   = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o %i -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o %i -j MASQUERADE

Now just restart WireGuard like so $ sudo wg-quick down wg0 $ sudo wg-quick up wg0

Make Sure WireGuard Starts on Boot $ sudo systemctl enable wg-quick@wg0.service $ sudo systemctl restart wg-quick@wg0.service

Adding a Client Configuration

$ pivpn add This will ask you to name the client. Specify any name you like, such as “phone” Then, if using a mobile device you can view the QR code by running the below command and selecting the proper client configuration from the prompt. $ pivpn -qr N.B at this stage, if you try to use the connections you will get a DNS error, that is because we have not connected the pihole

PiHole, unbound and dnscrypt-proxy

On my servers I like to use PiHole (a AD-blocking DNS filter), with it I also use dnscrypt-proxy - a DNS over HTTPs service as otherwise your DNS requests go over the internet in plain text. I also use unbound which does do plaintext DNS requests but does them in such a way that makes it very hard to record your traffic. This proivdes redundancy when DNS providers go down.

  1. Install docker sudo apt install docker.io, enable on restart sudo systemctl enable docker
  2. Install docker-compose sudo curl -L "https://github.com/docker/compose/releases/download/1.28.6/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && sudo chmod +x /usr/local/bin/docker-compose
  3. mkdir docker && cd docker thensudo nano docker-compose.yml and paste the yml below
    • If your WireGuard IP is not 10.6.0.1 then modify it before running
    • Use ifconfig to confirm no networks are already using 172.16.0.0/16
  4. Ensure the wireguard service is running sudo wg-quick up wg0
  5. sudo docker-compose up -d looks for docker-compose.yml in the dir you are using and starts the containers
  6. sudo docker stop unbound then sudo nano unbound/unbound.conf
    • modify use-caps-for-id:yes to use-caps-for-id:no as it can can cause issues
    • edns-buffer-size: 1232 to edns-buffer-size: 1472 for the same reason
    • add so-rcvbuf: 1m anywhere
    • delete the 3 include lines near the bottom as we dont use these files
    • sudo docker start unbound
  7. sudo docker logs dnscrypt-proxy if you see a file not found error sudo nano ~/docker/dnscrypt-proxy/dnscrypt-proxy.toml and paste in this
  8. Some optional edits to dnscrypt-proxy.toml
    • Rotate between the fastest 8 resolvers (not jus 2) enable and edit lb_strategy = 'p8'. This will dilute the information recieved by any one 'bad' resolver.
    • Leave caching to pihole and unbound - edit cache_size = 100
    • bring min TTL in line with unbound - edit cache_min_ttl = 300
    • restart to apply changes sudo docker restart dnscrypt-proxy
    • [Optional] under [anonymised dns] add routes = [{ server_name='*', via=['*'] }], this will route your DNS requests via relays, increasing privacy but decreasing performance. read more.
    • sudo docker restart dnscrypt-proxy
  9. Check all is well with sudo docker inspect -f "{{.State.Health.Status}}" pihole or sudo docker container ls
    • Make a note of the password in sudo docker logs pihole
  10. Connect to the wirguard vpn and navigate to 10.6.0.1 using the password above

Creating A DNS Only Tunnel / Split-Tunnel in WireGuard

Obviously with WireGuard we can create a full tunnel, but with this setup we may just want to reduce this to only DNS traffic to enable the Ad-blocking and additional privacy features without routing all our internet traffic over the connection and thus limiting our speed to the ~20mbs oracle limit. How do we do this? Limit AllowedIPs in your wireguard client configuration. Example client configuration:

[Interface]
PrivateKey = <YOUR PRIVATE KEY>
Address = 10.6.0.3/24 # This is the internal wireguard and assignable range for this client
DNS = 10.6.0.1 # This should send all DNS traffic to the pihole (as long as the client does as it is told).
[Peer]
PublicKey = <YOUR PUBLIC KEY>
PresharedKey = <YOUR PRESHARED KEY>
AllowedIPs = 10.6.0.1/32 # Important part 0 Set it to DNS IP above. Use /24 if you want to enable clients to communicate iwth one-another
Endpoint = <YOUR ORACLE/PIHOLE PUBLIC IP>:51820 

What does this do? Setting DNS = 10.6.0.1 it tells the device to send all DNS traffic to that address - hopefully the device listens. By setting AllowedIPs to be equal to the oracle/pihole IP, it will only sned traffic that is directed at our DNS (10.6.0.1) to be sent through the tunnel. Effectively creating a 'split-tunnel' - DNS traffic over the tunnel, everything else over the internet.

Optimising DNS Speed

PiHole is conservative when forwarding DNS requests. Usually one specifies two upstream DNS servers - in our case whichever provider DNScrypt picks and unbound. PiHole will trial both servers for a few requests and then pick the fastest average responder. It will use that responder for a the next 1000 or so requests and then play the game again. Unbound will nearly always lose this fight because it has to do a lot of legwork itself - it's speed comes after it has been running for a while and then builds its cache (and proactively keeps it updated). However it never gets the chance because PiHole will send nearly all its requests to the faster dnscrypt. It will only send requests to unbound in the event that dnscrypt goes down, this provides redundancy.

Luckily DNS-masq, the software pihole is built on, has a feature to send requests to both servers simultaneously and use the result from the first responder.

Note doing this will slightly decrease your privacy - because more requests will go out, dnscrypt providers will have a more complete picture of your browsing (although they say they don't collect this info, and as above most requests probably went to them anyway) and many more requests will go out via Unbound (although as the cache builds less and less will go out, and what does will be less synchronised with your browsing behaviour)

  1. cd ~/docker/etc-dnsmasq.d enter the dnsmasq configuration directory - dnsmasq will read all files in alpahnumeric order, later comands overwrite earlier ones
  2. confirm you are in the right directory with ls you should just see 01-pihole.conf
  3. echo "all-servers" > 09-all-servers.conf create a configuration file that enables all servers
  4. ls again and cat 09-all-servers.conf to confirm the file now exists
  5. sudo docker restart pihole restart the pihole to make the settings take effect
  6. After a few weeks when unbound will have 'learnt' all it needs to and built a big cache, consider disabling the above as it should now be a fairer fight between dnscrypt and unbound.

N.B this will slightly confuse your logs - discussed here

Copying your local pihole config

Go to your local pihole admin page, login then settings -> teleporter -> backup

Then navigate to 10.6.0.1/admin login, settings -> teleporter -> select file (unselect local DNS records and static DHCP)

Add the local record

Add the dns address you configured so you can log in to pihole when you want to Domain my.dns.address IP: 10.6.0.1

version: "3.7"
services:
pihole:
container_name: pihole
image: pihole/pihole:latest
dns: 127.0.0.1
restart: always
ports:
- 10.6.0.1:53:53/tcp
- 10.6.0.1:53:53/udp
- 10.6.0.1:67:67/udp
- 10.6.0.1:80:80/tcp
- 10.6.0.1:443:443/tcp
environment:
DNS1: 172.16.251.3#53
DNS2: 172.16.251.4#5053
IPv6: "no"
TZ: Europe/London
PROXY_LOCATION: pihole
DNSMASQ_LISTENING: single
cap_add:
- NET_ADMIN
volumes:
- ./etc-pihole/:/etc/pihole/ #use a .env file to set, eg. DOCKER_CONFIGS=/whatever_folder_you_want
- ./etc-dnsmasq.d/:/etc/dnsmasq.d/
networks:
pihole_net:
ipv4_address: 172.16.251.2
unbound:
container_name: unbound
image: mvance/unbound:latest
restart: always
# Enable if you want to give access to devices other than the pihole container
# ports:
# - 10.6.0.1:5054:53/tcp
# - 10.6.0.1:5054:53/udp
volumes:
- ./unbound/:/opt/unbound/etc/unbound
networks:
pihole_net:
ipv4_address: 172.16.251.3
dnscrypt-proxy:
container_name: dnscrypt-proxy
image: klutchell/dnscrypt-proxy:latest
ports:
- 10.6.0.1:5053:5053/tcp
- 10.6.0.1:5053:5053/udp
volumes:
- ./dnscrypt-proxy/:/config/
restart: unless-stopped
networks:
pihole_net:
ipv4_address: 172.16.251.4
# Enable if you want to remote manage the containers with portainer
# portainer-agent:
# container_name: portainer-agent
# image: portainer/agent:latest
# ports:
# - 10.6.0.1:9001:9001
# restart: unless-stopped
# volumes:
# - /var/run/docker.sock:/var/run/docker.sock
# - /var/lib/docker/volumes:/var/lib/docker/volumes
networks:
pihole_net:
name: pihole_net
driver: bridge
ipam:
config:
- subnet: 172.16.251.0/24
gateway: 172.16.251.1
@burjuyz
Copy link

burjuyz commented Sep 5, 2021

Huge thanks for your manual. Everything seems to work for me, but i have some questions.

  1. When I test on https://ipleak.net/ it shows me a lot of dns, and different ones while refreshing. Is this worked dns-crypt or what?
  2. How to make self check that everything is work well?

@HarvsG
Copy link
Author

HarvsG commented Oct 1, 2021

@burjuyz Expected behaviour of dnscrypt - it queries lots of different DNS servers - to find the fastest and also so no one DNS server knows your browsing habits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment