Recently, I have been tinkering with setting up DoH locally on MacOS, so I will record the process.
There are different solutions, such as using smartdns or dnscrypt-proxy + dnsmasq.
I also wrote a uTools plugin to quickly switch DNS.
What is DoH#
To understand what DoH is, you can refer to: https://en.wikipedia.org/wiki/DNS_over_HTTPS.
Using smartdns-rs#
smartdns-rs is a cross-platform local DNS server written in Rust. It obtains the fastest website IP and provides the best internet experience. It supports DoH and DoT.
Open source on GitHub: https://github.com/mokeyish/smartdns-rs
Using this software makes it very convenient to use DoH.
Download the binary file for your system from the releases page, unzip it, and then execute:
# Install and start the service
sudo ./smartdns service install
sudo ./smartdns service start
# Stop the service
# sudo ./smartdns service stop
# Uninstall the service
# sudo ./smartdns service uninstall
At this point, the software will install itself to /usr/local/bin/smartdns
, and in the future, you only need to execute smartdns
to control the behavior of the service.
The default configuration file used by the service is: /usr/local/etc/smartdns/smartdns.conf
. You can check the official documentation for specific parameters:
Simply add the following configuration to the bottom of this file:
# ... Default configuration
# server-tls dns.alidns.com
# server-https https://cloudflare-dns.com/dns-query
# server-https https://dns.alidns.com/dns-query
server-tls 8.8.8.8:853
server-https https://223.5.5.5/dns-query
smartdns
will listen on port 53 of the local machine by default.
Using dnsmasq & dnscrypt-proxy#
The tools used are dnscrypt-proxy + dnsmasq.
dnscrypt-proxy is responsible for initiating DoH requests.
dnsmasq is a lightweight domain name resolution server that forwards DNS requests to dnscrypt-proxy and forwards domain names within certain company domains to upstream DNS distributed by the router.
Installing dnsmasq and dnscrypt-proxy#
Installation is simple, using brew:
brew install dnsmasq dnscrypt-proxy
Installing locationchanger#
Execute:
curl -L https://github.com/eprev/locationchanger/raw/master/locationchanger.sh | bash
Then paste the following code at the end of the location changer script /usr/local/bin/locationchanger
:
DEFAULT_SCRIPT="$HOME/.locations/default"
if [ -f "$DEFAULT_SCRIPT" ]; then
ts "Running default '$DEFAULT_SCRIPT'"
"$DEFAULT_SCRIPT"
fi
This way, the script will run when we connect to the network.
Then create a file $HOME/.locations/default
:
mkdir -p $HOME/.locations && touch $HOME/.locations/default
The content is as follows:
#!/usr/bin/env bash
DNS=`ipconfig getpacket en0|grep domain_name_server|awk -F"[{,}]" '{print $2}'`
echo "$DNS"
echo "nameserver $DNS" > "$HOME/upstream.conf"
This command will write the DNS issued by the router to the file $HOME/upstream.conf
.
Then manually execute locationchanger
once to generate this file.
Configuration#
Configuring dnsmasq#
Check where brew prompts you for the configuration file, for example, on my M1 Mac, brew prompts that the configuration file is located at /opt/homebrew/etc/dnsmasq.conf
:
Then modify the contents of this configuration file:
# Only resolve domain names
domain-needed
bogus-priv
# Upstream DNS address distributed by the router we just generated
resolv-file=/Users/xxx/upstream.conf
# Listening address of dnscrypt-proxy configured below
server=127.0.0.1#5553
# Listening address of dnsmasq
listen-address=127.0.0.1
# Output logs for troubleshooting
log-queries
log-facility=/var/log/dnsmasq.log
Configuring dnscrypt-proxy#
The configuration file address for M1 Mac is: /opt/homebrew/etc/dnscrypt-proxy.toml
Here is my personal configuration. I only keep one DoH from Alibaba Cloud, and I comment out all the contents under sources. This way, the startup will be much faster.
If you keep the contents under sources, the software will have to find the fastest DNS every time it starts, which takes a long time.
# Listening address
listen_addresses = ['127.0.0.1:5553']
# Output logs for troubleshooting
log_file = '/var/log/dnscrypt-proxy.log'
# Configure alidns
[static]
[static.'alidns-doh']
stamp = 'sdns://AgAAAAAAAAAACTIyMy41LjUuNSCoF6cUD2dwqtorNi96I2e3nkHPSJH1ka3xbdOglmOVkQ5kbnMuYWxpZG5zLmNvbQovZG5zLXF1ZXJ5'