Introduction
Standard DNS lacks encryption capabilities, with all queries by default being transmitted as plaintext over UDP. Some responses with large byte results are truncated and transmitted via TCP (retrying in TCP mode), but these are still plaintext. In highly secure business environments, DNS encryption becomes crucial to avoid hijacking, pollution, and other security threats. This is where DNS over HTTPS (DoH) and DNS over TLS (DoT) come into play. Additionally, HTTPDNS can prevent operator hijacking issues by bypassing the ISPâs LDNS and directly requesting HTTPDNS services. This offers [domain hijacking prevention](https://cloud.tencent.com/product/httpdns?from_column=20065&from=20065), precise scheduling, and other features, but is mainly oriented towards mobile app scenarios. The resolution process is as follows:

Returning to the main topic, dnscrypt-proxy serves as a DoH/DoT DNS forwarding service. Combined with existing DoH/DoT public services in the industry, it easily achieves DNS encrypted transmission.
Based on this, it is necessary to route domestic and foreign domains to different DoH/DoT resolutions to improve resolution efficiency and accuracy. This is achieved using dnsmasq
+ dnscrypt-proxy
, with the architecture as follows:

The installation and configuration of dnsmasq will not be detailed here; you can refer to the previous article.
1. Installing dnscrypt-proxy
1. Installing from Software Source
Most distribution software repositories come with dnscrypt-proxy included, and itâs recommended to choose this installation method as it will automatically set up the systemd service.
Distribution |
Installation Command |
---|---|
Arch |
pacman -Sy dnscrypt-proxy/yay -Sy dnscrypt-proxy |
CentOS/RedHat |
yum install -y dnscrypt-proxy |
Debian/Ubuntu |
apt-get install -y dnscrypt-proxy |
2. Binary Installation
(1) Obtaining
Download the latest version from the releases page:
cd /opt # Habitually place it in the /opt directory; you can also place it in the /etc directory or elsewhere
wget https://github.com/DNSCrypt/dnscrypt-proxy/releases/download/2.1.2/dnscrypt-proxy-linux_x86_64-2.1.2.tar.gz
As of November 2022, the latest version is 2.1.2.
(2) Extracting and Creating a Symlink
tar xvf dnscrypt-proxy-linux_x86_64-2.1.2.tar.gz
mv linux-x86_64 dnscrypt-proxy
cd dnscrypt-proxy
ln -sf /opt/dnscrypt-proxy/dnscrypt-proxy /usr/sbin/dnscrypt-proxy
- Rename for better readability, youâll see an executable dnscrypt-proxy file and some sample configuration files after extraction.
- Create a symlink to the executable in the PATH directory.
(3) Creating a systemd Service
vim /etc/systemd/system/dnscrypt-proxy.service
Insert the following content:
[Unit]
Description=Encrypted/authenticated DNS proxy
ConditionFileIsExecutable=/usr/sbin/dnscrypt-proxy
[Service]
StartLimitInterval=5
StartLimitBurst=10
ExecStart=/usr/sbin/dnscrypt-proxy "-config" "dnscrypt-proxy.toml"
WorkingDirectory=/opt/dnscrypt-proxy
Restart=always
RestartSec=120
EnvironmentFile=-/etc/sysconfig/dnscrypt-proxy
[Install]
WantedBy=multi-user.target
Reload the systemd daemon:
systemctl daemon-reload
Enable at startup:
systemctl enable dnscrypt-proxy.service
2. Public Servers and Service Configuration Rewrite
1. Temporarily Test Resolution
The file example-dnscrypt-proxy.toml
in the directory is the main configuration file. Copy it to use as the official configuration file:
cp example-dnscrypt-proxy.toml dnscrypt-proxy.toml
Before starting via systemctl, it can be run in the foreground:
./dnscrypt-proxy "-config" "dnscrypt-proxy.toml"
Test if the resolution is normal:
./dnscrypt-proxy -resolve google.com

You should be able to resolve addresses normally. From the logs, you can see that by default, it requests built-in DoH servers. Since most of these DoH servers are overseas, the ability to access them securely is a fundamental requirement if you are in China.
2. DoH/DoT Service List
(1) Public Servers
The dnscrypt-proxy official provides a service list (may require secure internet access within China) where you can choose the servers to use as upstream DNS from the supported list.
Currently, Tsinghua and Alibabaâs DoH servers are the only supported ones within China:


(2) Public Servers Map
Additionally, a map search method is also provided, with the supported points marked on the map:

This facilitates selecting the closest DoH upstream server to you.
3. Configuration File Rewrite
Based on the need for domestic and overseas routing, two configuration files are required, one for domestic and one for overseas.
(1) Domestic Configuration
Most built-in functions of dnscrypt-proxy.toml
are unnecessary. Here, dnscrypt-proxy.toml
is rewritten as:
# Empty listen_addresses to use systemd socket activation
listen_addresses = ['0.0.0.0:5533']
server_names = ['alidns-doh','tuna-doh-ipv4']
cache_size = 4096
cache_min_ttl = 2400
cache_max_ttl = 86400
cache_neg_min_ttl = 60
cache_neg_max_ttl = 600
[query_log]
file = â/var/log/dnscrypt-proxy/query.logâ
[nx_log]
file = â/var/log/dnscrypt-proxy/nx.logâ
[sources]
[sources.âpublic-resolversâ] url = âhttps://download.dnscrypt.info/resolvers-list/v2/public-resolvers.mdâ cache_file = â/var/cache/dnscrypt-proxy/public-resolvers.mdâ minisign_key = âRWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3â refresh_delay = 72 prefix = â
- The listening address here is set to 5533 instead of 53 to prevent conflicts with system-built DNS services.
server_names
are the defined upstream DoH/DoT servers and must be chosen from the service list.
(2) Foreign Configuration
Copy dnscrypt-proxy.toml
to create a new file:
cp dnscrypt-proxy.toml dnscrypt-proxy-foreign.toml
Change server_names
to overseas DoH/DoT servers and modify the listening port. The example after modification is as follows; other parts need not be edited:
listen_addresses = ['0.0.0.0:25533']
server_names = ['cloudflare','google']
4. Writing a systemd Service
The domestic configuration is already written in systemd, and the same applies to foreign configuration, requiring a process to listen and run.
vim /etc/systemd/system/dnscrypt-proxy-foreign.service
Insert the following content:
[Unit]
Description=Encrypted/authenticated DNS proxy
ConditionFileIsExecutable=/usr/sbin/dnscrypt-proxy
[Service]
StartLimitInterval=5
StartLimitBurst=10
ExecStart=/usr/sbin/dnscrypt-proxy "-config" "dnscrypt-proxy-foreign.toml"
WorkingDirectory=/opt/dnscrypt-proxy
Restart=always
RestartSec=120
EnvironmentFile=-/etc/sysconfig/dnscrypt-proxy
[Install]
WantedBy=multi-user.target
Reload the systemd daemon:
systemctl daemon-reload
Enable at startup:
systemctl enable dnscrypt-proxy-foreign.service
3. Start and Test Validation
3.1. Start
Load a toml configuration file for both domestic and foreign servers, with the corresponding systemd services already set up. Next, start them and verify if they meet expectations.
systemctl start dnscrypt-proxy.service
systemctl start dnscrypt-proxy-foreign.service

The service runs properly, with 5533 listening for domestic domains and 25533 for foreign domains.
2. Test Validation
At this point, intelligent domestic and foreign routing has not been implemented, so first separately verify if both services resolve normally.
View the resolution log file:
tail -f /var/log/dnscrypt-proxy/query.log
Test different ports using the dig command to see which upstream DNS is used:
dig qcloud.com @192.168.1.72 -p 5533 +short
dig youtube.com @192.168.1.72 -p 25533 +short

This indicates that both services are operating well.
4. Implementing Intelligent Domain Splitting with Dnsmasq
1. Modifying Dnsmasq Upstream DNS
If dnsmasq isnât yet installed and configured, refer to the previous article up to the step of achieving domestic and foreign routing on a dnsmasq dimension using dnsmasq-china-list
.
Next, just change the upstream DNS to the machine running dnscrypt-proxy. If dnsmasq and dnscrypt-proxy are on the same machine, change it to the local address.
(1) Specifying Domestic Upstream DoH Listening Address
In China, modify accelerated-domains.china.conf
in dnsmasq-china-list
, replacing the IP with the domestic DoH listening address:
sed -i 's|114.114.114.114|127.0.0.1#5533|g' accelerated-domains.china.conf
The result should look like server=/0-100.com/127.0.0.1#5533
As I have two services running independently on two systems, replace it with the domestic DoH listening address of the machine running dnscrypt-proxy:

(2) Specifying Foreign Upstream DoH Listening Address
Since resolv.conf
canât specify a port, upstream DNS for foreign DoH needs to be defined in dnsmasq.conf
. So here, /etc/resolv.conf
writes the local address, and dnsmasq.conf
adds a configuration to the foreign DoH listening address:
$ cat /etc/resolv.conf
nameserver 127.0.0.1
$ cat /etc/dnsmasq.conf
log-queries
log-facility=/var/log/dnsmasq.log
no-hosts
bogus-nxdomain=119.29.29.29
cache-size=1000
port=53
# The following configuration is added, #25533 is not a comment but specifies the port. If dnsmasq and dnscrypt-proxy run on the same machine, replace with 127.0.0.1#25533
server=192.168.1.72#25533
(3) iptables DNAT Rule
Based on the expansion scheme of #(2), this is an optional step. You can choose either method, applicable if dnsmasq and dnscrypt-proxy run on different machines.
If you prefer not to specify the server in dnsmasq.conf
as a foreign DoH address and set it directly in /etc/resolv.conf
, you only need to make a DNAT rule on the dnscrypt-proxy machine that directs port 53 to the foreign DoH listening port:
# Replace 192.168.1.72 with the internal IP of the dnscrypt-proxy machine
iptables -t nat -A PREROUTING -i ens192 -p tcp --dport 53 -j DNAT --to-destination 192.168.1.72:25533
iptables -t nat -A PREROUTING -i ens192 -p udp --dport 53 -j DNAT --to-destination 192.168.1.72:25533

At this point, modify the /etc/resolv.conf
file content on the dnsmasq machine to:
nameserver 192.168.1.72
2. Verifying DoH/DoT Intelligent Splitting Scenarios
Use any internal machine and change the DNS resolution to the dnsmasq machine address, then access domestic and foreign domains for testing and validation.
Machine |
Role/Service |
---|---|
192.168.1.71 |
Client, DNS pointing to dnsmasq |
192.168.1.72 |
dnscrypt-proxy |
192.168.1.73 |
dnsmasq |
(1) Log Verification
If you follow my above configuration to set up, the corresponding log file paths are:
- dnsmasq query log path:
/var/log/dnsmasq.log
- dnscrypt-proxy query log path:
/var/log/dnscrypt-proxy/query.log
Use the dig command to test, and monitor the output of the corresponding log file:

It is clear that for domestic domain resolution, dnsmasq forwards to the domestic upstream DoH of dnscrypt-proxy; for foreign domain resolution, it forwards to the foreign upstream DoH. Cache records are controlled by dnsmasq, and repeated requests directly hit the cache, returning the result to the client.
(2) Packet Capture Verification
dig github.com
is used as a verification example:

Deploy packet capture on both the dnsmasq and dnscrypt-proxy machines:
On the dnsmasq machine:
tcpdump -i any -nn -s 0 port 53 or port 5533 or port 25533 or port 443 -v -w dnsmasq.pcap
On the dnscrypt-proxy machine:
tcpdump -i any -nn -s 0 port 53 or port 5533 or port 25533 or port 443 -v -w dnscrypt-proxy.pcap
Later, download the .pcap
files locally, and use Wireshark to analyze them as follows:
- dnsmasq: Packet 9, receiving DNS query request from the client;
- dnsmasq: Packet 10, dnsmasq requests the upstream dnscrypt-proxy;
- dnscrypt-proxy: Packet 5, dnscrypt-proxy receives the DNS query request from dnsmasq;
- dnscrypt-proxy: Packets 6-30, establish a TCP three-way handshake and TLS handshake with upstream Google DoH, encrypting DNS requests;
- dnscrypt-proxy: Packets 31-33, receive encrypted response data;
- dnscrypt-proxy: Packet 34, decrypts and returns the resolution result to dnsmasq;
- dnsmasq: Packet 11, receives the resolution record;
- dnsmasq: Packet 12, returns the result to the client.

It is clear to see, dnsmasq receives the request and forwards it to the foreign DoH server for processing. This process goes through TLS-encrypted transmission, greatly ensuring DNS security. The request is received and decrypted before returning to the client normally.
Summary
With this, dnsmasq
+ dnscrypt-proxy
to implement domestic and overseas DoH/DoT split resolution is completed. The principle is very simple: the dnsmasq machine serves as the entry point, using the dnsmasq-china-list
mainland domain whitelist for forwarding and splitting to upstream dnscrypt-proxy, and dnscrypt-proxy then forwards the encrypted results to corresponding DoH/DoT public servers.
Additionally, dnscrypt-proxy has load balancing capabilities, which can be specified in the toml
configuration file by the lb_strategy
parameter. Potential settings include:
first
: Always choose the fastest server in the listp2
: Randomly choose from the top 2 fastest servers, default optionph
: Randomly choose among the fastest half of all serversrandom
: Randomly select from the Server list
Adjust based on different business scenarios, and select a few high-quality upstream DoH/DoT, moderately increasing the number of RS for optimal selection.
PDF version attached:
dnscrpt-proxy+dnsmasq advanced application â implementation of DoH, DoT.pdfdnscrpt-proxy+dnsmasq advanced application â implementation of DoH, DoT.pdf (Light version).pdf