how not to self-host adguard dns
i wish LLMs had peaked the self-hosting help department, but sadly they haven't. fuck chatgpt and all the moronic LLMs that couldn't assist me in my deployment of adguard dns for my personal usage (i am just kidding, don't fuck them. just in case the ai overlords rise one day and come to kill me, please forgive me my lords, i am a peasant who was just kidding)
i don't know who it was, but i vividly remember hearing someone say once, "i have no clue about what to do. the only thing i know is what not to". seems like that's the motto.
note just incase you don't end up reading the whole thing (because of course no one does): if you are a friend and someone i know, feel free to ping me for help, if you try to self host or if you want access to my dns server.
what even is adguard and why did i do this to myself
adguard home is basically a network-wide ad blocker. instead of installing adblock on every device, you point all your stuff to use this as their dns server and boom - no ads anywhere. phone, smart tv, tablet, whatever.
sounds cool right? it is. except i decided to self-host it at 2am on a 1gb ram azure vm because i'm a broke student who values "control" and "privacy" over sanity. the alternative was paying $2/month for nextdns. obviously spending 48 hours debugging was the logical choice.
(but does my site track you? sorry, it does. i too like data. but don't worry, i use umami instead of google analytics)
mistake #1: thinking azure would be easy
first thing you need to do is login to azure.microsoft.com, which for some reason is a big task in itself. if you haven't seen the website, please go look at it. why someone in good frigging conscience would design this monstrosity. the page physically hurts my eyes.
mistake #2: the yunohost rabbit hole
i had this brilliant idea to use yunohost because it supposedly makes self-hosting easy. except yunohost only works on debian 12. and azure doesn't have debian 12 images in india. image unavailable for some reason.

so i googled which ubuntu version is based on debian 12. turns out it's ubuntu 22.04 LTS. perfect! except no.

yunohost won't install on ubuntu either. this was the moment i realized people don't self-host because it's a choice. people don't self-host because there's no choice. no average person wants to deal with this crackedness after midnight.
mistake #3: casaos seemed like a good idea
i installed casaos. then immediately uninstalled it. why? because my tiny cute 1gb ram machine had 700mb occupied by casaos sitting idle. yeah, no thanks.
mistake #4: docker will make things easier (narrator: it didn't)
everyone says docker makes things easier. so i set up docker-compose like a good little developer:
version: '3'
services:
adguard:
image: adguard/adguardhome
container_name: adguard
ports:
- "53:53/tcp"
- "53:53/udp"
except docker added another layer of bullshit to debug. permissions were fucked. certificates didn't work. volume mounts were confusing. every time i wanted to edit something, i had to docker exec into the container like i'm in the matrix.
worst part? whenever i bound port 53 in docker and then stopped the container, my entire network would shit itself and ssh would die. i'd have to reset the vm from azure portal like a caveman.
eventually i said fuck it, ditched docker, and installed adguard natively. suddenly half my problems disappeared.
lesson learned: docker is great until it isn't. for a simple dns server on 1gb ram, native installation is better.
mistake #5: port 531 seemed reasonable
since port 53 kept killing my ssh, i moved dns to port 531. problem solved, right?
wrong. android phones don't allow custom dns ports. you can't just type "531" anywhere in the settings. there's no field for it. phones only work with standard ports using encrypted dns.
i spent hours testing why my phone wouldn't connect before realizing this.
mistake #6: not understanding cloudflare proxy
so i set up an A record pointing to my server. tried to query it:
$ dig @subdomain.mydomain.com google.com -p 531
;; communications error to [cloudflare-ip]#531: timed out
but direct ip worked fine:
$ dig @[my-vm-ip] google.com -p 531
;; Got answer:
then it clicked. cloudflare proxy. the orange cloud. that motherfucker.
when cloudflare proxy is on (orange cloud), they only forward HTTP/HTTPS on ports 80 and 443. everything else - dns, custom ports, ssh - gets blocked. my dns queries were hitting cloudflare's edge and getting dropped.
the fix: turn the proxy off. grey cloud that subdomain. suddenly everything worked.
mistake #7: trying to use https with an ip address
i wanted my dashboard at https://[my-vm-ip]/. got let's encrypt certificates. pasted them into adguard. clicked save.
service bricks. dashboard gone. browser says connection failed.
then the revelation hit me: let's encrypt doesn't issue certificates for IP addresses. only domain names.
so my cert for subdomain.mydomain.com won't work when accessing via IP. browsers say no. android says hell no.
mistake #8: thinking cloudflare certificates would work
cloudflare gives free SSL certificates that last 15 years! perfect, right?
except they're only trusted by cloudflare's proxy. phones don't trust them. browsers don't trust them. they're signed by cloudflare's private CA, not a public one.
so cloudflare origin certs only work when proxy is ON. but when proxy is ON, cloudflare blocks dns traffic.
catch-22.
what actually worked (eventually)
after 48 hours of pain, here's what finally worked:
-
native installation, not docker. just install adguard directly on ubuntu.
-
cloudflare proxy OFF (grey cloud) for the dns subdomain.
-
let's encrypt via adguard's automatic feature. it handles everything.
-
DNS-over-HTTPS and DNS-over-TLS enabled. this is what phones actually need.
-
open the right ports in azure: 53, 80, 443, 853.
android settings:
- go to private dns
- enter your subdomain
- if it says "connected", you won. if not, something's still fucked.
things i learned the hard way
- docker adds complexity when you don't need it
- cloudflare proxy blocks everything except http/https
- let's encrypt doesn't do IP addresses
- android requires encrypted dns (DoH/DoT)
- port 53 on linux is cursed because of systemd-resolved
- certificate file permissions matter
- azure's UI is a crime against design
was it worth it?
total time enjoyed (or wasted): 48 hours
total money saved vs nextdns: $2/month
was it worth it: hell yea, i love chaos.
would i do it again: ask me after therapy
but hey, everything works now. my phone uses my dns server. ads are blocked. i can see query logs. i feel like a hackerman.
well, maybe.
ask me again tomorrow.
edit: all my life, my isp has been gtpl. lately, i also have airtel and frigging airtel literally doesn't want you to change settings. the input field to change dns are disabled. also after that, the save button is hidden by default and you have to change the setting, to see it.

edit again:
someone sent 2 lakh requests to my server at night. you little shits, i will block each one of you. he made request to sikelocci dot com while i was asleep. my poor vm almost died and apparently adguard also went dead for a while in the middle of the night, because i can see traffic drop and also my phone showing dns not working in the morning. f you you moron.

if you made it this far, i salute you. if you're trying to do the same thing, good luck. you'll need it. and maybe therapy afterward.