Setup dnscrypt-proxy on Ubuntu 24.04 (Raspberry Pi 5)

This will setup dnscrypt-proxy as the only DNS on Ubuntu Server.

  1. Change from DHCP to Static IP
    create a backup of /etc/netplan/50-cloud-init.yaml

    $ sudo cp /etc/netplan/50-cloud-init.yaml /etc/netplan/50-cloud-init.yaml.bak

    and then copy below structure for static IP

    network:
        ethernets:
            eth0:
                dhcp4: no
                addresses:
                  - 192.168.X.X/25
                routes:
                  - to: default
                    via: 192.168.X.X
                nameservers:
                  addresses: [127.0.0.1,X.X.X.X,Y.Y.Y.Y]
                optional: true
        version: 2

    and then apply the new netplan

    $ sudo netplan apply
  2. Install dnscrypt-proxy
    $ sudo apt install dnscrypt-proxy
  3. create a backup of /etc/dnscrypt-proxy/dnscrypt-proxy.toml
    $ sudo cp /etc/dnscrypt-proxy/dnscrypt-proxy.toml /etc/dnscrypt-proxy/dnscrypt-proxy.toml.bak

    and then use your config based on your preference what is important is below:

    server_names = ['doh.tiar.app', 'doh.tiar.app-doh', 'doh.tiar.app-ipv6', 'doh.tiar.app-doh-ipv6','id-gmail', 'id-gmail-doh', 'id-gmail-ipv6', 'id-gmail-doh-ipv6','cloudflare','cloudflare-ipv6','cloudflare-security','cloudflare-security-ipv6']
    
    listen_addresses = []
    
    fallback_resolvers = ['9.9.9.9:53', '8.8.8.8:53']
    
    [sources.'public-resolvers']
    urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v2/public-resolvers.md', 'https://download.dnscrypt.info/resolvers-list/v2/public-resolvers.md']
    cache_file = '/var/cache/dnscrypt-proxy/public-resolvers.md'
    minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
    prefix = ''
    

    for the complete example:

    ##############################################
    # #
    # dnscrypt-proxy configuration #
    # #
    ##############################################
    
    ## This is an example configuration file.
    ## You should adjust it to your needs, and save it as "dnscrypt-proxy.toml"
    ##
    ## Online documentation is available here: https://dnscrypt.info/doc
    
    ##################################
    # Global settings #
    ##################################
    
    ## List of servers to use
    ##
    ## Servers from the "public-resolvers" source (see down below) can
    ## be viewed here: https://dnscrypt.info/public-servers
    ##
    ## The proxy will automatically pick working servers from this list.
    ## Note that the require_* filters do NOT apply when using this setting.
    ##
    ## By default, this list is empty and all registered servers matching the
    ## require_* filters will be used instead.
    ##
    ## Remove the leading # first to enable this; lines starting with # are ignored.
    
    server_names = ['doh.tiar.app', 'doh.tiar.app-doh', 'doh.tiar.app-ipv6', 'doh.tiar.app-doh-ipv6','id-gmail', 'id-gmail-doh', 'id-gmail-ipv6', 'id-gmail-doh-ipv6','cloudflare','cloudflare-ipv6','cloudflare-security','cloudflare-security-ipv6']
    
    ## List of local addresses and ports to listen to. Can be IPv4 and/or IPv6.
    ## Example with both IPv4 and IPv6:
    listen_addresses = []
    
    # listen_addresses = ['127.0.0.1:53']
    
    ## Maximum number of simultaneous client connections to accept
    
    max_clients = 250
    
    ## Switch to a different system user after listening sockets have been created.
    ## Note (1): this feature is currently unsupported on Windows.
    ## Note (2): this feature is not compatible with systemd socket activation.
    ## Note (3): when using -pidfile, the PID file directory must be writable by the new user
    
    # user_name = 'nobody'
    
    ## Require servers (from static + remote sources) to satisfy specific properties
    
    # Use servers reachable over IPv4
    ipv4_servers = true
    
    # Use servers reachable over IPv6 -- Do not enable if you don't have IPv6 connectivity
    ipv6_servers = false
    
    # Use servers implementing the DNSCrypt protocol
    dnscrypt_servers = true
    
    # Use servers implementing the DNS-over-HTTPS protocol
    doh_servers = true
    
    ## Require servers defined by remote sources to satisfy specific properties
    
    # Server must support DNS security extensions (DNSSEC)
    require_dnssec = false
    
    # Server must not log user queries (declarative)
    require_nolog = true
    
    # Server must not enforce its own blacklist (for parental control, ads blocking...)
    require_nofilter = true
    
    # Server names to avoid even if they match all criteria
    disabled_server_names = []
    
    ## Always use TCP to connect to upstream servers.
    ## This can be useful if you need to route everything through Tor.
    ## Otherwise, leave this to `false`, as it doesn't improve security
    ## (dnscrypt-proxy will always encrypt everything even using UDP), and can
    ## only increase latency.
    
    force_tcp = false
    
    ## SOCKS proxy
    ## Uncomment the following line to route all TCP connections to a local Tor node
    ## Tor doesn't support UDP, so set `force_tcp` to `true` as well.
    
    # proxy = 'socks5://127.0.0.1:9050'
    
    ## HTTP/HTTPS proxy
    ## Only for DoH servers
    
    # http_proxy = 'http://127.0.0.1:8888'
    
    ## How long a DNS query will wait for a response, in milliseconds.
    ## If you have a network with *a lot* of latency, you may need to
    ## increase this. Startup may be slower if you do so.
    ## Don't increase it too much. 10000 is the highest reasonable value.
    
    timeout = 5000
    
    ## Keepalive for HTTP (HTTPS, HTTP/2) queries, in seconds
    
    keepalive = 30
    
    ## Response for blocked queries. Options are `refused`, `hinfo` (default) or
    ## an IP response. To give an IP response, use the format `a:,aaaa:`.
    ## Using the `hinfo` option means that some responses will be lies.
    ## Unfortunately, the `hinfo` option appears to be required for Android 8+
    
    # blocked_query_response = 'refused'
    
    ## Load-balancing strategy: 'p2' (default), 'ph', 'first' or 'random'
    
    # lb_strategy = 'p2'
    
    ## Set to `true` to constantly try to estimate the latency of all the resolvers
    ## and adjust the load-balancing parameters accordingly, or to `false` to disable.
    
    # lb_estimator = true
    
    ## Log level (0-6, default: 2 - 0 is very verbose, 6 only contains fatal errors)
    
    # log_level = 2
    
    ## Log file for the application, as an alternative to sending logs to
    ## the standard system logging service (syslog/Windows event log).
    ##
    ## This file is different from other log files, and will not be
    ## automatically rotated by the application.
    
    # log_file = 'dnscrypt-proxy.log'
    
    ## When using a log file, only keep logs from the most recent launch.
    
    # log_file_latest = true
    
    ## Use the system logger (syslog on Unix, Event Log on Windows)
    
    # use_syslog = true
    
    ## Delay, in minutes, after which certificates are reloaded
    
    cert_refresh_delay = 240
    
    ## DNSCrypt: Create a new, unique key for every single DNS query
    ## This may improve privacy but can also have a significant impact on CPU usage
    ## Only enable if you don't have a lot of network load
    
    # dnscrypt_ephemeral_keys = false
    
    ## DoH: Disable TLS session tickets - increases privacy but also latency
    
    # tls_disable_session_tickets = false
    
    ## DoH: Use a specific cipher suite instead of the server preference
    ## 49199 = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    ## 49195 = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    ## 52392 = TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
    ## 52393 = TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
    ## 4865 = TLS_AES_128_GCM_SHA256
    ## 4867 = TLS_CHACHA20_POLY1305_SHA256
    ##
    ## On non-Intel CPUs such as MIPS routers and ARM systems (Android, Raspberry Pi...),
    ## the following suite improves performance.
    ## This may also help on Intel CPUs running 32-bit operating systems.
    ##
    ## Keep tls_cipher_suite empty if you have issues fetching sources or
    ## connecting to some DoH servers. Google and Cloudflare are fine with it.
    
    # tls_cipher_suite = [52392, 49199]
    
    ## Fallback resolvers
    ## These are normal, non-encrypted DNS resolvers, that will be only used
    ## for one-shot queries when retrieving the initial resolvers list, and
    ## only if the system DNS configuration doesn't work.
    ## No user application queries will ever be leaked through these resolvers,
    ## and they will not be used after IP addresses of resolvers URLs have been found.
    ## They will never be used if lists have already been cached, and if stamps
    ## don't include host names without IP addresses.
    ## They will not be used if the configured system DNS works.
    ## Resolvers supporting DNSSEC are recommended.
    ##
    ## People in China may need to use 114.114.114.114:53 here.
    ## Other popular options include 8.8.8.8 and 1.1.1.1.
    ##
    ## If more than one resolver is specified, they will be tried in sequence.
    
    fallback_resolvers = ['9.9.9.9:53', '8.8.8.8:53']
    
    ## Always use the fallback resolver before the system DNS settings.
    
    ignore_system_dns = true
    
    ## Maximum time (in seconds) to wait for network connectivity before
    ## initializing the proxy.
    ## Useful if the proxy is automatically started at boot, and network
    ## connectivity is not guaranteed to be immediately available.
    ## Use 0 to not test for connectivity at all (not recommended),
    ## and -1 to wait as much as possible.
    
    netprobe_timeout = 60
    
    ## Address and port to try initializing a connection to, just to check
    ## if the network is up. It can be any address and any port, even if
    ## there is nothing answering these on the other side. Just don't use
    ## a local address, as the goal is to check for Internet connectivity.
    ## On Windows, a datagram with a single, nul byte will be sent, only
    ## when the system starts.
    ## On other operating systems, the connection will be initialized
    ## but nothing will be sent at all.
    
    netprobe_address = '9.9.9.9:53'
    
    ## Offline mode - Do not use any remote encrypted servers.
    ## The proxy will remain fully functional to respond to queries that
    ## plugins can handle directly (forwarding, cloaking, ...)
    
    # offline_mode = false
    
    ## Additional data to attach to outgoing queries.
    ## These strings will be added as TXT records to queries.
    ## Do not use, except on servers explicitly asking for extra data
    ## to be present.
    ## encrypted-dns-server can be configured to use this for access control
    ## in the [access_control] section
    
    # query_meta = ["key1:value1", "key2:value2", "token:MySecretToken"]
    
    ## Automatic log files rotation
    
    # Maximum log files size in MB - Set to 0 for unlimited.
    log_files_max_size = 10
    
    # How long to keep backup files, in days
    log_files_max_age = 7
    
    # Maximum log files backups to keep (or 0 to keep all backups)
    log_files_max_backups = 1
    
    #########################
    # Filters #
    #########################
    
    ## Note: if you are using dnsmasq, disable the `dnssec` option in dnsmasq if you
    ## configure dnscrypt-proxy to do any kind of filtering (including the filters
    ## below and blacklists).
    ## You can still choose resolvers that do DNSSEC validation.
    
    ## Immediately respond to IPv6-related queries with an empty response
    ## This makes things faster when there is no IPv6 connectivity, but can
    ## also cause reliability issues with some stub resolvers.
    
    block_ipv6 = false
    
    ## Immediately respond to A and AAAA queries for host names without a domain name
    
    block_unqualified = true
    
    ## Immediately respond to queries for local zones instead of leaking them to
    ## upstream resolvers (always causing errors or timeouts).
    
    block_undelegated = true
    
    ## TTL for synthetic responses sent when a request has been blocked (due to
    ## IPv6 or blacklists).
    
    reject_ttl = 600
    
    ##################################################################################
    # Route queries for specific domains to a dedicated set of servers #
    ##################################################################################
    
    ## See the `example-forwarding-rules.txt` file for an example
    
    # forwarding_rules = 'forwarding-rules.txt'
    
    ###############################
    # Cloaking rules #
    ###############################
    
    ## Cloaking returns a predefined address for a specific name.
    ## In addition to acting as a HOSTS file, it can also return the IP address
    ## of a different name. It will also do CNAME flattening.
    ##
    ## See the `example-cloaking-rules.txt` file for an example
    
    # cloaking_rules = 'cloaking-rules.txt'
    
    ## TTL used when serving entries in cloaking-rules.txt
    
    # cloak_ttl = 600
    
    ###########################
    # DNS cache #
    ###########################
    
    ## Enable a DNS cache to reduce latency and outgoing traffic
    
    cache = true
    
    ## Cache size
    
    cache_size = 4096
    
    ## Minimum TTL for cached entries
    
    cache_min_ttl = 2400
    
    ## Maximum TTL for cached entries
    
    cache_max_ttl = 86400
    
    ## Minimum TTL for negatively cached entries
    
    cache_neg_min_ttl = 60
    
    ## Maximum TTL for negatively cached entries
    
    cache_neg_max_ttl = 600
    
    ##################################
    # Local DoH server #
    ##################################
    
    [local_doh]
    
    ## dnscrypt-proxy can act as a local DoH server. By doing so, web browsers
    ## requiring a direct connection to a DoH server in order to enable some
    ## features will enable these, without bypassing your DNS proxy.
    
    ## Addresses that the local DoH server should listen to
    
    # listen_addresses = ['127.0.0.1:3000']
    
    ## Path of the DoH URL. This is not a file, but the part after the hostname
    ## in the URL. By convention, `/dns-query` is frequently chosen.
    ## For each `listen_address` the complete URL to access the server will be:
    ## `https://` (ex: `https://127.0.0.1/dns-query`)
    
    # path = "/dns-query"
    
    ## Certificate file and key - Note that the certificate has to be trusted.
    ## See the documentation (wiki) for more information.
    
    # cert_file = "localhost.pem"
    # cert_key_file = "localhost.pem"
    
    ###############################
    # Query logging #
    ###############################
    
    ## Log client queries to a file
    
    [query_log]
    
    ## Path to the query log file (absolute, or relative to the same directory as the config file)
    ## On non-Windows systems, can be /dev/stdout to log to the standard output (also set log_files_max_size to 0)
    
    # file = 'query.log'
    
    ## Query log format (currently supported: tsv and ltsv)
    
    format = 'tsv'
    
    ## Do not log these query types, to reduce verbosity. Keep empty to log everything.
    
    # ignored_qtypes = ['DNSKEY', 'NS']
    
    ############################################
    # Suspicious queries logging #
    ############################################
    
    ## Log queries for nonexistent zones
    ## These queries can reveal the presence of malware, broken/obsolete applications,
    ## and devices signaling their presence to 3rd parties.
    
    [nx_log]
    
    ## Path to the query log file (absolute, or relative to the same directory as the config file)
    
    # file = 'nx.log'
    
    ## Query log format (currently supported: tsv and ltsv)
    
    format = 'tsv'
    
    ######################################################
    # Pattern-based blocking (blacklists) #
    ######################################################
    
    ## Blacklists are made of one pattern per line. Example of valid patterns:
    ##
    ## example.com
    ## =example.com
    ## *sex*
    ## ads.*
    ## ads*.example.*
    ## ads*.example[0-9]*.com
    ##
    ## Example blacklist files can be found at https://download.dnscrypt.info/blacklists/
    ## A script to build blacklists from public feeds can be found in the
    ## `utils/generate-domains-blacklists` directory of the dnscrypt-proxy source code.
    
    [blacklist]
    
    ## Path to the file of blocking rules (absolute, or relative to the same directory as the config file)
    
    # blacklist_file = 'blacklist.txt'
    
    ## Optional path to a file logging blocked queries
    
    # log_file = 'blocked.log'
    
    ## Optional log format: tsv or ltsv (default: tsv)
    
    # log_format = 'tsv'
    
    ###########################################################
    # Pattern-based IP blocking (IP blacklists) #
    ###########################################################
    
    ## IP blacklists are made of one pattern per line. Example of valid patterns:
    ##
    ## 127.*
    ## fe80:abcd:*
    ## 192.168.1.4
    
    [ip_blacklist]
    
    ## Path to the file of blocking rules (absolute, or relative to the same directory as the config file)
    
    # blacklist_file = 'ip-blacklist.txt'
    
    ## Optional path to a file logging blocked queries
    
    # log_file = 'ip-blocked.log'
    
    ## Optional log format: tsv or ltsv (default: tsv)
    
    # log_format = 'tsv'
    
    ######################################################
    # Pattern-based whitelisting (blacklists bypass) #
    ######################################################
    
    ## Whitelists support the same patterns as blacklists
    ## If a name matches a whitelist entry, the corresponding session
    ## will bypass names and IP filters.
    ##
    ## Time-based rules are also supported to make some websites only accessible at specific times of the day.
    
    [whitelist]
    
    ## Path to the file of whitelisting rules (absolute, or relative to the same directory as the config file)
    
    # whitelist_file = 'whitelist.txt'
    
    ## Optional path to a file logging whitelisted queries
    
    # log_file = 'whitelisted.log'
    
    ## Optional log format: tsv or ltsv (default: tsv)
    
    # log_format = 'tsv'
    
    ##########################################
    # Time access restrictions #
    ##########################################
    
    ## One or more weekly schedules can be defined here.
    ## Patterns in the name-based blocklist can optionally be followed with @schedule_name
    ## to apply the pattern 'schedule_name' only when it matches a time range of that schedule.
    ##
    ## For example, the following rule in a blacklist file:
    ## *.youtube.* @time-to-sleep
    ## would block access to YouTube during the times defined by the 'time-to-sleep' schedule.
    ##
    ## {after='21:00', before= '7:00'} matches 0:00-7:00 and 21:00-0:00
    ## {after= '9:00', before='18:00'} matches 9:00-18:00
    
    [schedules]
    
    # [schedules.'time-to-sleep']
    # mon = [{after='21:00', before='7:00'}]
    # tue = [{after='21:00', before='7:00'}]
    # wed = [{after='21:00', before='7:00'}]
    # thu = [{after='21:00', before='7:00'}]
    # fri = [{after='23:00', before='7:00'}]
    # sat = [{after='23:00', before='7:00'}]
    # sun = [{after='21:00', before='7:00'}]
    
    # [schedules.'work']
    # mon = [{after='9:00', before='18:00'}]
    # tue = [{after='9:00', before='18:00'}]
    # wed = [{after='9:00', before='18:00'}]
    # thu = [{after='9:00', before='18:00'}]
    # fri = [{after='9:00', before='17:00'}]
    
    #########################
    # Servers #
    #########################
    
    ## Remote lists of available servers
    ## Multiple sources can be used simultaneously, but every source
    ## requires a dedicated cache file.
    ##
    ## Refer to the documentation for URLs of public sources.
    ##
    ## A prefix can be prepended to server names in order to
    ## avoid collisions if different sources share the same for
    ## different servers. In that case, names listed in `server_names`
    ## must include the prefixes.
    ##
    ## If the `urls` property is missing, cache files and valid signatures
    ## must already be present. This doesn't prevent these cache files from
    ## expiring after `refresh_delay` hours.
    
    [sources]
    
    ## An example of a remote source from https://github.com/DNSCrypt/dnscrypt-resolvers
    
    [sources.'public-resolvers']
    urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v2/public-resolvers.md', 'https://download.dnscrypt.info/resolvers-list/v2/public-resolvers.md']
    cache_file = '/var/cache/dnscrypt-proxy/public-resolvers.md'
    minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
    prefix = ''
    
    ## Anonymized DNS relays
    
    [sources.'relays']
    urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v2/relays.md', 'https://download.dnscrypt.info/resolvers-list/v2/relays.md']
    cache_file = '/var/cache/dnscrypt-proxy/relays.md'
    minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
    refresh_delay = 72
    prefix = ''
    
    ## Quad9 over DNSCrypt - https://quad9.net/
    
    # [sources.quad9-resolvers]
    # urls = ['https://www.quad9.net/quad9-resolvers.md']
    # minisign_key = 'RWQBphd2+f6eiAqBsvDZEBXBGHQBJfeG6G+wJPPKxCZMoEQYpmoysKUN'
    # cache_file = 'quad9-resolvers.md'
    # prefix = 'quad9-'
    
    ## Another example source, with resolvers censoring some websites not appropriate for children
    ## This is a subset of the `public-resolvers` list, so enabling both is useless
    
    # [sources.'parental-control']
    # urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v2/parental-control.md', 'https://download.dnscrypt.info/resolvers-list/v2/parental-control.md']
    # cache_file = 'parental-control.md'
    # minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
    
    #########################################
    # Servers with known bugs #
    #########################################
    
    [broken_implementations]
    
    # Cisco servers currently cannot handle queries larger than 1472 bytes, and don't
    # truncate reponses larger than questions as expected by the DNSCrypt protocol.
    # This prevents large responses from being received over UDP and over relays.
    #
    # The `dnsdist` server software drops client queries larger than 1500 bytes.
    # They are aware of it and are working on a fix.
    #
    # The list below enables workarounds to make non-relayed usage more reliable
    # until the servers are fixed.
    
    fragments_blocked = ['cisco', 'cisco-ipv6', 'cisco-familyshield', 'cisco-familyshield-ipv6', 'quad9-dnscrypt-ip4-filter-alt', 'quad9-dnscrypt-ip4-filter-pri', 'quad9-dnscrypt-ip4-nofilter-alt', 'quad9-dnscrypt-ip4-nofilter-pri', 'quad9-dnscrypt-ip6-filter-alt', 'quad9-dnscrypt-ip6-filter-pri', 'quad9-dnscrypt-ip6-nofilter-alt', 'quad9-dnscrypt-ip6-nofilter-pri', 'cleanbrowsing-adult', 'cleanbrowsing-family-ipv6', 'cleanbrowsing-family', 'cleanbrowsing-security']
    
    #################################################################
    # Certificate-based client authentication for DoH #
    #################################################################
    
    # Use a X509 certificate to authenticate yourself when connecting to DoH servers.
    # This is only useful if you are operating your own, private DoH server(s).
    # 'creds' maps servers to certificates, and supports multiple entries.
    # If you are not using the standard root CA, an optional "root_ca"
    # property set to the path to a root CRT file can be added to a server entry.
    
    [doh_client_x509_auth]
    
    #
    # creds = [
    # { server_name='myserver', client_cert='client.crt', client_key='client.key' }
    # ]
    
    ################################
    # Anonymized DNS #
    ################################
    
    [anonymized_dns]
    
    ## Routes are indirect ways to reach DNSCrypt servers.
    ##
    ## A route maps a server name ("server_name") to one or more relays that will be
    ## used to connect to that server.
    ##
    ## A relay can be specified as a DNS Stamp (either a relay stamp, or a
    ## DNSCrypt stamp), an IP:port, a hostname:port, or a server name.
    ##
    ## The following example routes "example-server-1" via `anon-example-1` or `anon-example-2`,
    ## and "example-server-2" via the relay whose relay DNS stamp
    ## is "sdns://gRIxMzcuNzQuMjIzLjIzNDo0NDM".
    ##
    ## !!! THESE ARE JUST EXAMPLES !!!
    ##
    ## Review the list of available relays from the "relays.md" file, and, for each
    ## server you want to use, define the relays you want connections to go through.
    ##
    ## Carefully choose relays and servers so that they are run by different entities.
    ##
    ## "server_name" can also be set to "*" to define a default route, but this is not
    ## recommended. If you do so, keep "server_names" short and distinct from relays.
    
    # routes = [
    # { server_name='example-server-1', via=['anon-example-1', 'anon-example-2'] },
    # { server_name='example-server-2', via=['sdns://gRIxMzcuNzQuMjIzLjIzNDo0NDM'] }
    # ]
    
    # skip resolvers incompatible with anonymization instead of using them directly
    
    skip_incompatible = false
    
    ###############################
    # DNS64 #
    ###############################
    
    ## DNS64 is a mechanism for synthesizing AAAA records from A records.
    ## It is used with an IPv6/IPv4 translator to enable client-server
    ## communication between an IPv6-only client and an IPv4-only server,
    ## without requiring any changes to either the IPv6 or the IPv4 node,
    ## for the class of applications that work through NATs.
    ##
    ## There are two options to synthesize such records:
    ## Option 1: Using a set of static IPv6 prefixes;
    ## Option 2: By discovering the IPv6 prefix from DNS64-enabled resolver.
    ##
    ## If both options are configured - only static prefixes are used.
    ## (Ref. RFC6147, RFC6052, RFC7050)
    ##
    ## Do not enable unless you know what DNS64 is and why you need it, or else
    ## you won't be able to connect to anything at all.
    
    [dns64]
    
    ## (Option 1) Static prefix(es) as Pref64::/n CIDRs.
    # prefix = ["64:ff9b::/96"]
    
    ## (Option 2) DNS64-enabled resolver(s) to discover Pref64::/n CIDRs.
    ## These resolvers are used to query for Well-Known IPv4-only Name (WKN) "ipv4only.arpa." to discover only.
    ## Set with your ISP's resolvers in case of custom prefixes (other than Well-Known Prefix 64:ff9b::/96).
    ## IMPORTANT: Default resolvers listed below support Well-Known Prefix 64:ff9b::/96 only.
    # resolver = ["[2606:4700:4700::64]:53", "[2001:4860:4860::64]:53"]
    
    ########################################
    # Static entries #
    ########################################
    
    ## Optional, local, static list of additional servers
    ## Mostly useful for testing your own servers.
    
    [static]
    
    # [static.'myserver']
    # stamp = 'sdns:AQcAAAAAAAAAAAAQMi5kbnNjcnlwdC1jZXJ0Lg'
    
  4. Stop and disable the systemd-resolved service
    
    
    
    $ sudo systemctl stop systemd-resolved.service
    $ sudo systemctl disable systemd-resolved.service

  5. Create these files and ensure the permission are correct
    $ sudo touch /var/cache/dnscrypt-proxy/public-resolvers.md
    $ sudo touch /var/cache/dnscrypt-proxy/public-resolvers.md.minisig
    $ sudo touch /var/cache/dnscrypt-proxy/relays.md
    $ sudo touch /var/cache/dnscrypt-proxy/relays.md.minisig
    $ sudo chown _dnscrypt-proxy:nogroup /var/cache/dnscrypt-proxy/public-resolvers.md
    $ sudo chown _dnscrypt-proxy:nogroup /var/cache/dnscrypt-proxy/public-resolvers.md.minisig
    $ sudo chown _dnscrypt-proxy:nogroup /var/cache/dnscrypt-proxy/relays.md
    $ sudo chown _dnscrypt-proxy:nogroup /var/cache/dnscrypt-proxy/relays.md.minisig
    $ sudo chmod 644 /var/cache/dnscrypt-proxy/public-resolvers.md
    $ sudo chmod 644 /var/cache/dnscrypt-proxy/public-resolvers.md.minisig
    $ sudo chmod 644 /var/cache/dnscrypt-proxy/relays.md
    $ sudo chmod 644 /var/cache/dnscrypt-proxy/relays.md.minisig
  6. Disable the DNSStub
    $ sudo nano /etc/systemd/resolved.conf

    remove the comment and change below to no

    DNSStubListener=no
  7. stop the dnscrypt-proxy socket service and change the IP
    $ sudo systemctl stop dnscrypt-proxy.socket
    $ sudo nano /usr/lib/systemd/system/dnscrypt-proxy.socket

    Modify below option

    ListenStream=127.0.0.1:53
    ListenDatagram=127.0.0.1:53
  8. Reboot the server
    $ sudo reboot

Check if everything works as intention

  1. Check your configuration:
    $ dnscrypt-proxy -check -config /etc/dnscrypt-proxy/dnscrypt-proxy.toml

  2. Test resolve DNS with dnscrypt-proxy
    $ sudo dnscrypt-proxy -resolve reddit.com -config /etc/dnscrypt-proxy/dnscrypt-proxy.toml

  3. Dig from previous DNS

    to dnscrypt-proxy