dnscrypt-proxy on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of dnscrypt-proxy on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. dnscrypt-proxy is a flexible DNS proxy that encrypts your DNS traffic. It sits between your clients and the public internet: it accepts ordinary DNS queries on port 53 and forwards every one of them to a public upstream resolver over an encrypted transport, so your Internet provider and any network on the path can no longer see or tamper with the names you look up. It supports the modern encrypted DNS protocols including DNSCrypt v2, DNS over HTTPS, Anonymized DNSCrypt and Oblivious DoH.
The image installs dnscrypt-proxy 2.1.18 from the official prebuilt release binary, run under systemd as an unprivileged dnscrypt-proxy user with just the CAP_NET_BIND_SERVICE capability so it can bind the standard privileged DNS port. It answers DNS on port 53 over both UDP and TCP on all interfaces and forwards to upstreams chosen automatically from a cryptographically signed public resolver list by lowest latency. There is no web interface and no database: a single flat TOML file (/etc/dnscrypt-proxy/dnscrypt-proxy.toml) is the whole configuration.
Secure by default. Upstream selection is restricted to resolvers that validate DNSSEC, keep no logs, and apply no filtering, so you get authentic, private, unfiltered answers. The image ships with no shared or default credential of any kind, since dnscrypt-proxy has no login. It binds all interfaces so it can serve a whole network, but the stock Azure Network Security Group opens only SSH, so port 53 is not reachable from the internet until you deliberately open it. Because dnscrypt-proxy has no built in allow from access control list, the Network Security Group is your access control: open UDP and TCP 53 only to the client subnets you control, never to the whole internet, so the resolver is never abused as an open resolver.
What is included:
-
dnscrypt-proxy 2.1.18 from the official prebuilt release binary, run under systemd as the unprivileged
dnscrypt-proxyuser (dnscrypt-proxy.service) -
A DNS endpoint on
0.0.0.0:53(UDP and TCP) that forwards every query to an encrypted upstream (DNSCrypt v2 or DNS over HTTPS) -
Automatic selection of DNSSEC validating, no log, non filtering encrypted resolvers from a minisign signed public resolver list
-
The whole configuration in one readable file,
/etc/dnscrypt-proxy/dnscrypt-proxy.toml, with ready to edit example blocklists, allow lists, cloaking and forwarding rules alongside it -
The systemd-resolved stub listener disabled so dnscrypt-proxy owns port 53 cleanly, while the OS keeps resolving names through its own upstream list
Prerequisites
-
Active Azure subscription, SSH public key, VNet + subnet in target region
-
Subscription to the dnscrypt-proxy listing on Azure Marketplace
-
Network Security Group rules allowing TCP 22 (admin) and UDP 53 + TCP 53 (DNS) only from the client subnets that will use the resolver
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) is ample for a departmental resolver. dnscrypt-proxy is extremely light; larger sizes are only needed for very high query volumes.
Step 1: Deploy from the Azure Portal
Search dnscrypt-proxy in Marketplace, select the cloudimg publisher, and click Create. Configure the Network Security Group to allow TCP 22 for administration and UDP 53 and TCP 53 from the clients that will use the resolver. Keep port 53 scoped to your own client subnets, never 0.0.0.0/0.
Step 2: Deploy from the Azure CLI
RG="dns-prod"; LOCATION="eastus"; VM_NAME="dnscrypt1"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/dnscrypt-proxy-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az vm create \
--resource-group "$RG" --name "$VM_NAME" \
--image "$GALLERY_IMAGE_ID" \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values "$SSH_KEY" \
--public-ip-sku Standard
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 22 --priority 1001
Do not open port 53 with a blanket az vm open-port. Add a scoped Network Security Group rule for UDP and TCP 53 that lists only your client subnets as the source (see Step 7).
Step 3: First boot
On first boot the image writes a per instance informational note to /root/dnscrypt-proxy-info.txt, refreshes the signed resolver list into its cache, and starts dnscrypt-proxy. This completes within seconds. SSH in as azureuser and read the note:
sudo cat /root/dnscrypt-proxy-info.txt
The note records the version, the listen address, this VM's IP, the config path and the encrypted only upstream policy. dnscrypt-proxy has no password, so the note holds no secret.
Step 4: Confirm the service is running
dnscrypt-proxy.service is active, dnscrypt-proxy -version reports 2.1.18, and it runs as the unprivileged dnscrypt-proxy user. ss confirms it is listening on :53 for DNS over both UDP and TCP on all interfaces.
systemctl is-active dnscrypt-proxy.service
/opt/dnscrypt-proxy/dnscrypt-proxy -version
sudo ss -tulnp | grep ':53 '

Step 5: Resolve a name through the encrypted resolver
Send an ordinary DNS query to the resolver on the loopback address. dnscrypt-proxy forwards it to an encrypted upstream and returns the answer. DNS over TCP works too, which clients fall back to for large responses.
dig +noall +answer @127.0.0.1 example.com A
dig +tcp +noall +answer @127.0.0.1 cloudflare.com A
Both queries return normal A records. Your client sees plain DNS on port 53, while dnscrypt-proxy has transparently fetched the answer over an encrypted transport on your behalf.

Step 6: Confirm the upstreams are encrypted
This is the property that matters for a privacy resolver. dnscrypt-proxy logs each live upstream and the protocol it speaks (DNSCrypt or DoH) as it measures latency, and picks the fastest. The -resolve subcommand shows a full diagnostic for a name, including that the answer is DNSSEC validated.
sudo journalctl -u dnscrypt-proxy --no-pager | grep -E 'OK \(DNSCrypt\)|OK \(DoH\)|lowest initial latency' | tail -5
/opt/dnscrypt-proxy/dnscrypt-proxy -config /etc/dnscrypt-proxy/dnscrypt-proxy.toml -resolve example.com | grep -iE 'Resolver|Name servers|DNSSEC'
Every upstream is OK (DNSCrypt) or OK (DoH) — never plain DNS — and DNSSEC signed : yes confirms the answer was cryptographically validated end to end.

Step 7: Secure by default and restrict the Network Security Group
The shipped configuration only ever selects encrypted, DNSSEC validating, no log, non filtering upstreams. Review the policy, then lock down access. dnscrypt-proxy has no built in allow from access control list, so the Network Security Group is your access control.
grep -E '^(listen_addresses|require_dnssec|require_nolog|require_nofilter|dnscrypt_servers|doh_servers) ' /etc/dnscrypt-proxy/dnscrypt-proxy.toml
In the Azure Portal, add an inbound Network Security Group rule for UDP 53 and TCP 53 whose Source is your own client subnets (for example your VNet address space or a specific 10.0.0.0/24), and set the source to your admin IP for TCP 22. Never set the source of the port 53 rule to Any or 0.0.0.0/0 — an internet reachable resolver with no allow list is an open resolver and can be abused for amplification.

Step 8: Point your clients at the resolver
Once the Network Security Group allows your subnets, point your clients or your VNet's DNS setting at this VM's private IP on port 53. To make the whole virtual network use the resolver, set it as the VNet's custom DNS server:
# From your workstation, using the Azure CLI (VNET_RG / VNET_NAME are your VNet's):
# az network vnet update -g <VNET_RG> -n <VNET_NAME> --dns-servers <this-vm-private-ip>
# Then reboot (or re-apply DHCP on) the client VMs so they pick up the new resolver.
echo "Set your VNet custom DNS to this VM's private IP, or configure clients directly."
Individual Linux clients can test against the resolver directly with dig @<this-vm-private-ip> example.com.
Step 9: Choose specific upstreams or protocols
By default dnscrypt-proxy selects automatically from all resolvers that match the encrypted, DNSSEC, no log and no filter requirements. To pin a specific set, uncomment and edit server_names in the config, then restart. To use only DNS over HTTPS (or only DNSCrypt), set the matching *_servers toggles.
# edit /etc/dnscrypt-proxy/dnscrypt-proxy.toml, for example:
# server_names = ['cloudflare', 'google', 'quad9-doh-ip4-port443-nofilter-pri']
# or restrict to a single protocol:
# dnscrypt_servers = false # DoH only
# then apply the change:
# sudo systemctl restart dnscrypt-proxy
echo "See https://github.com/DNSCrypt/dnscrypt-proxy/wiki for the full server list and options."
The configuration is validated on start; if there is a syntax error the service fails to start and logs the reason, so check systemctl status dnscrypt-proxy after any edit.
Step 10: Optional blocklists, allow lists and cloaking
dnscrypt-proxy ships with ready to edit example rule files in /etc/dnscrypt-proxy. Enable name blocklists, IP blocklists, cloaking (local overrides) or per name forwarding by pointing the matching section of the config at a rules file.
ls /etc/dnscrypt-proxy/example-*.txt
Copy an example to a working file (for example blocked-names.txt), reference it from the [blocked_names] section of the config, and restart. This lets you filter ads or malware domains, pin internal names, or forward a private zone to an internal resolver, all without an external service.
Step 11: Security recommendations
-
Scope the Network Security Group. Allow UDP 53 and TCP 53 only from the client subnets you control. dnscrypt-proxy has no allow from ACL, so the NSG is the only thing standing between your resolver and the internet.
-
Keep the encrypted only upstream policy. Leave
require_dnssec,require_nologandrequire_nofilterset to true so answers stay authentic, private and unfiltered. -
Prefer trusted upstreams for sensitive networks. Pin
server_namesto operators you trust, or enable Anonymized DNSCrypt or Oblivious DoH so no single upstream sees both your IP and your queries. -
Keep the OS patched. Unattended security upgrades remain enabled on the running VM.
Step 12: Support and Licensing
dnscrypt-proxy is an open source project distributed under the ISC License. This cloudimg image bundles the unmodified official dnscrypt-proxy release binary. cloudimg provides the packaging, the systemd hardening, the secure by default encrypted only upstream policy, the per instance first boot automation, the paired deploy guide, and 24/7 support with a guaranteed 24 hour response SLA.
cloudimg is not affiliated with or endorsed by the dnscrypt-proxy project or its authors. dnscrypt-proxy is a mark of its respective owner and is used here only to identify the software.
Deploy on Azure
Find dnscrypt-proxy on Ubuntu 24.04 LTS on the Azure Marketplace, published by cloudimg. Deploy from the Portal or the Azure CLI as shown above.
Need Help?
Email support@cloudimg.co.uk for deployment help, configuration questions, or licensing enquiries.