Showing posts with label DNS. Show all posts
Showing posts with label DNS. Show all posts

Friday, 7 August 2026

Splitting One Domain Across GitHub Pages and Blogger: A Complete DNS Setup Guide

 


If you own a single domain but want to run two separate things on it — say, a static landing page on GitHub Pages at the root domain, and a blog on Blogger at a subdomain — you'll quickly discover that the actual mechanics of DNS, custom domain verification, and HTTPS certificate provisioning are scattered across three different systems that don't talk to each other and don't always explain their errors clearly.

This post documents the full setup, end to end: what records you need, what each provider actually requires, and the specific errors you're likely to hit along the way (all of which I hit myself while setting this up).

The goal, concretely:

  • example.com (the apex/root domain) → a static site hosted on GitHub Pages
  • blog.example.com (a subdomain) → a Blogger blog, with its original xxxx.blogspot.com address redirecting to it
  • www.example.com → optionally also works, redirecting to the apex

I'll use bojankomazec.com as the running example, since that's the domain I set this up on.


1. The Big Picture: Three Systems, One Domain

Before touching any settings, it helps to understand the three layers involved and what each one owns:


Layer

What it controls

Where you configure it

DNS registrar (e.g. GoDaddy, Namecheap, Cloudflare)

Which records exist for your domain — A, CNAME, MX, etc. This is the actual "phone book" that tells the internet where to send traffic.

Your registrar's DNS management panel
GitHub Pages

Which domain(s) it will accept and serve your static site for, and whether it issues an HTTPS certificate for them

Repository → Settings → Pages

BloggerWhich domain(s) it will accept and serve your blog for, and whether it issues an HTTPS certificate for themBlogger → Settings → Publishing

The critical thing to understand: DNS records alone are not enough. Both GitHub Pages and Blogger require you to also tell them, inside their own settings, which custom domain you're using. If DNS points to them but their own settings don't know about your domain, you'll get connection errors — not because DNS is wrong, but because the receiving service doesn't recognize the incoming hostname and refuses it.

This is the single most common source of confusion in this kind of setup: DNS can be 100% correct and the site can still fail to load, because DNS and application-level domain configuration are two separate steps that both have to be done.


2. DNS Records You'll Need

Here's the full set, using bojankomazec.com as the example domain, blog as the subdomain, and bojankomazec as the GitHub username (so the Pages repo is bojankomazec.github.io).

Apex domain → GitHub Pages

DNS doesn't allow a CNAME record at the apex/root of a domain (technically, because the apex must also hold other record types like SOA and often MX, and a hostname can't mix CNAME with anything else). So GitHub Pages publishes a fixed set of IP addresses, and you point the apex at those directly with A records:

Type: A    Host: @    Value: 185.199.108.153
Type: A    Host: @    Value: 185.199.109.153
Type: A    Host: @    Value: 185.199.110.153
Type: A    Host: @    Value: 185.199.111.153

(@ is the conventional way most DNS panels represent "the apex/root domain itself.") If your provider supports IPv6 and you want dual-stack support, GitHub also publishes AAAA records:

Type: AAAA    Host: @    Value: 2606:50c0:8000::153
Type: AAAA    Host: @    Value: 2606:50c0:8001::153
Type: AAAA    Host: @    Value: 2606:50c0:8002::153
Type: AAAA    Host: @    Value: 2606:50c0:8003::153

Important: check whether your registrar auto-created a placeholder A record for @ when the domain was registered (many do, often pointing to a parking page). If so, delete it — a leftover default record will conflict with the four you're adding.

www subdomain → GitHub Pages (optional)

If you also want www.example.com to work (redirecting to the apex once GitHub verifies both), add:

Type: CNAME    Host: www    Value: bojankomazec.github.io.

Note this points to your GitHub Pages hostname (<username>.github.io), not to a URL, and not to the repo's github.com page. A CNAME value is always a hostname, never a full URL with https:// or a path.

Blog subdomain → Blogger

Type: CNAME    Host: blog    Value: ghs.google.com.

This is the one that trips people up: it's tempting to point this directly at your xxxx.blogspot.com address, since that's "where the blog lives." Don't do that. Blogger's custom-domain routing works through a shared Google endpoint (ghs.google.com) that inspects the incoming hostname and routes it to the correct blog based on what's configured in your Blogger account. Pointing the CNAME straight at your blogspot address sends the request to blogspot-specific infrastructure that doesn't know how to handle a request arriving under a different hostname — the connection gets abruptly closed rather than serving anything (ERR_CONNECTION_CLOSED in Chrome).

Blogger domain verification CNAME

Separately from the routing CNAME above, Blogger needs to confirm you actually own the subdomain before it'll accept it. When you enter your custom domain into Blogger's settings, it will generate a unique verification CNAME — something like:

Type: CNAME    Host: <random-string>    Value: gv-<random-string>.dv.googlehosted.com.

This value is generated per-domain and per-account — you can't predict or reuse it, you have to copy it exactly from Blogger's settings screen after entering your custom domain. Add it as its own DNS record alongside the routing CNAME.

Gotcha: if you ever change which subdomain Blogger is using (e.g. you originally set it up as www.example.com and later switch to blog.example.com), the old verification CNAME becomes stale and should be deleted — Blogger will issue a new one specific to the new subdomain when you re-save.

Full example record set

A       @        185.199.108.153
A       @        185.199.109.153
A       @        185.199.110.153
A       @        185.199.111.153
CNAME   www      bojankomazec.github.io.
CNAME   blog     ghs.google.com.
CNAME   <verify> gv-xxxxxxxxxxxx.dv.googlehosted.com.

3. The GitHub Pages Side

  1. In your <username>.github.io repository, go to Settings → Pages.
  2. Under Custom domain, enter your apex domain (e.g. bojankomazec.com — no www, no https://).
  3. Save. GitHub will write a file literally named CNAME (no extension) into the root of your repository, containing just the domain name. This file is how GitHub Pages knows which domain to serve your content for — DNS alone doesn't tell it this.
  4. GitHub will attempt to verify your DNS. If your A records are already correct, this usually succeeds quickly. If you see a DNS valid for primary message alongside a separate www.example.com is improperly configured warning — that's normal. The www check is a secondary, automatic check GitHub runs to see if it can also offer www support and a unified certificate; it doesn't block your primary domain from working. If your primary domain error clears and only the www one remains, your site is live.
  5. Once verified, tick Enforce HTTPS (this option is often greyed out until GitHub finishes issuing a certificate — see the HTTPS section below).

4. The Blogger Side

  1. In Blogger, go to Settings → Publishing.
  2. Under Custom domain, enter your blog subdomain (e.g. blog.bojankomazec.com).
  3. Save. Blogger will likely reject the save the first time and show you the verification CNAME described above. Copy it exactly.
  4. Add both the routing CNAME (ghs.google.com) and the verification CNAME to your DNS.
  5. Wait for propagation (see below), then go back and save again in Blogger. It should now accept the domain.
  6. Check the Redirect domain setting on the same page carefully — see the dedicated warning about this below, it's a common trap.
  7. Look for an HTTPS availability toggle further down the page. It usually reads "Status: Unknown" for a while after you first set up the domain — this is Blogger's certificate issuance still in progress, not an error (see HTTPS section).

The "Redirect domain" trap

Blogger's Publishing settings include a "Redirect domain" option, something like "Redirect example.com to blog.example.com." This setting, if enabled, makes Blogger redirect your apex domain to your blog. If your apex domain is meant to serve something else entirely (like a GitHub Pages landing page, as in this setup), this option will silently hijack it — visitors to example.com will get redirected to your blog instead of seeing your landing page, even though your DNS and GitHub Pages configuration are both completely correct.

This setting can also change target without obviously telling you: if you initially set up Blogger's custom domain as www.example.com and later switch it to blog.example.com, the "Redirect domain" checkbox may still be checked, just silently re-pointed at whatever your current custom domain is. If you don't want your apex domain touched by Blogger at all, make sure this is switched off, and re-check it any time you change Blogger's custom domain setting.


5. HTTPS and Certificates: Why It Takes a While

Both GitHub Pages and Blogger use automated certificate issuance (GitHub uses Let's Encrypt; Google's infrastructure handles Blogger's) that kicks in after your domain passes DNS verification — not before, and not instantly.

What this means in practice:

  • Your site can be fully reachable over plain http:// while https:// still fails, sometimes with a confusing certificate error, for anywhere from a few minutes to around 24–48 hours after you first set up or change a custom domain.
  • The specific error you'll likely see in Chrome during this window is something like:
  Your connection is not private
  net::ERR_CERT_COMMON_NAME_INVALID
  This server could not prove that it is www.example.com;
  its security certificate is from *.github.io

This happens because the connection is reaching GitHub's infrastructure, but GitHub hasn't yet issued a certificate specifically covering your hostname, so it falls back to serving its generic wildcard certificate — which your browser correctly flags as invalid for your domain.

  • Don't repeatedly remove and re-add the custom domain while waiting — each change can reset the certificate issuance queue and make the wait longer, not shorter.
  • Once issuance completes, https:// starts working with no further action needed on your part.

A red herring worth knowing about: antivirus HTTPS scanning

If you inspect your site's certificate in Chrome and see something unexpected — like the certificate authority being your antivirus software (Avast, Kaspersky, and others do this) rather than Let's Encrypt or Google — this is not a sign of a compromised or misconfigured site. Many antivirus suites include an "HTTPS scanning" or "Web Shield" feature that intercepts encrypted connections locally, decrypting and re-encrypting them with a certificate the antivirus generated and installed into your system's trust store, in order to scan traffic for threats.

This substitution happens for every HTTPS site you visit, not just yours, so it's not diagnostic of anything wrong with your setup. To see the actual certificate your host issued, either temporarily disable the antivirus's HTTPS scanning feature, or check from an external tool that doesn't go through your local machine at all — such as SSL Labs' SSL Test, which queries your server directly.


6. Troubleshooting Toolkit

A handful of tools make this whole process far less guess-and-check:

  • dig <domain> <record-type> (Mac/Linux, or Windows via WSL) — queries DNS directly and shows you exactly what's published, bypassing any local caching. E.g. dig bojankomazec.com A or dig blog.bojankomazec.com CNAME.
  • nslookup <domain> — similar, built into Windows natively.
  • dnschecker.org — checks DNS propagation across many resolvers worldwide simultaneously, which is invaluable for figuring out whether a record change has actually rolled out everywhere yet, or is still mid-propagation.
  • SSL Labs SSL Test — inspects a site's actual certificate chain independent of your local browser/antivirus interference.

General debugging approach when something doesn't load:

  1. Confirm the DNS record itself is correct and propagated (dnschecker.org).
  2. Confirm the receiving service (GitHub Pages / Blogger) has the domain configured in its own settings, not just DNS.
  3. Try plain http:// before https:// — this isolates whether the problem is routing/configuration (affects both) or just certificate issuance (only affects https).
  4. If a certificate error shows an unexpected issuer (like an antivirus name instead of Let's Encrypt/Google), suspect local HTTPS interception before suspecting your DNS setup.

7. Common Errors and What They Actually Mean

Error

What it usually means

InvalidCNAMEError (GitHub)

The named subdomain's CNAME doesn't point where GitHub expects, or DNS hasn't propagated to the resolver GitHub's checker used yet. Verify with dnschecker.org before assuming misconfiguration.

NotServedByPagesError (GitHub)

DNS looks fine, but the domain isn't yet resolving to GitHub Pages from GitHub's own check — often transient/propagation-related.

ERR_CERT_COMMON_NAME_INVALID

The connection reached the right server, but no certificate has been issued for this specific hostname yet — a provisioning delay, not a misconfiguration.

ERR_CONNECTION_CLOSED (on a Blogger subdomain)

Usually means the CNAME points somewhere that doesn't recognize the incoming hostname — most often, pointing directly at a .blogspot.com address instead of ghs.google.com.

A domain unexpectedly redirecting somewhere else entirely

Check Blogger's "Redirect domain" setting — it may be silently redirecting your apex domain to your blog.

Certificate issuer shown as an antivirus company

Local HTTPS scanning/interception by your antivirus software — check via an external tool instead.


8. Summary Checklist

  • Four A records for the apex domain, pointing at GitHub Pages' published IPs
  • (Optional) CNAME for www pointing at <username>.github.io
  • CNAME for your blog subdomain pointing at ghs.google.com (not directly at your .blogspot.com address)
  • Blogger's unique verification CNAME, copied exactly from its settings screen
  • Custom domain entered in GitHub Pages settings (creates the repo's CNAME file)
  • Custom domain entered in Blogger's Publishing settings
  • Blogger's "Redirect domain" setting switched off, unless you deliberately want your apex redirected to your blog
  • Patience for HTTPS certificate issuance (minutes to ~48 hours) on both platforms
  • Verify using http:// first, then https://, and cross-check unexpected certificate issuers against local antivirus software before assuming a server-side problem

Once all of this settles, you end up with a clean split: your apex domain serving whatever static site or landing page you want full control over, and a subdomain serving your blog — both fully on their own custom domains, both secured with HTTPS, and both surviving independently of where the underlying content is actually hosted.

Friday, 24 October 2025

Introduction to Kubernetes CoreDNS



CoreDNS is a DNS server that runs inside Kubernetes and is responsible for service discovery — i.e., translating service names (like my-service.default.svc.cluster.local) into IP addresses.


What CoreDNS Does

In a Kubernetes cluster:
  • Every Pod and Service gets its own DNS name.
  • CoreDNS listens for DNS queries from Pods (via /etc/resolv.conf).
  • It looks up the name in the cluster’s internal DNS records and returns the correct ClusterIP or Pod IP.
So if a Pod tries to reach mysql.default.svc.cluster.local, CoreDNS will resolve it to the IP of the mysql service.

How It Works

Runs as a Deployment in the kube-system namespace.
Has a Service called kube-dns (for backward compatibility).
Uses a ConfigMap (coredns) to define how DNS queries are processed.
Listens on port 53 (UDP/TCP), the standard DNS port.

Example CoreDNS ConfigMap snippet:

apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        health
        kubernetes cluster.local in-addr.arpa ip6.arpa {
            pods insecure
            fallthrough in-addr.arpa ip6.arpa
        }
        prometheus :9153
        forward . /etc/resolv.conf
        cache 30
        loop
        reload
        loadbalance
    }

Key Plugins


CoreDNS is modular — it uses plugins for specific functionality:
  • kubernetes: handles DNS for cluster Services/Pods.
  • forward: forwards queries to upstream resolvers for external domains.
  • cache: caches responses for faster resolution.
  • prometheus: exposes metrics for monitoring.
  • health: adds a health endpoint.

Why It Matters


Without CoreDNS, Pods can’t resolve service names.
It’s essential for communication between microservices.
It’s a critical cluster component — if it breaks, DNS resolution (and often your workloads) fail.

kubectl cluster-info reports two things and one of them is that CoreDNS is running. That's how important this service is!

% kubectl cluster-info 
Kubernetes control plane is running at https://94A57AXXXXX5184.gr7.us-east-1.eks.amazonaws.com
CoreDNS is running at https://94A57AXXXXX5184.gr7.us-east-1.eks.amazonaws.com/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

Common Commands


Check CoreDNS pods:

kubectl get pods -n kube-system -l k8s-app=kube-dns

We can also get all pods in the cluster and then filter CoreDNS ones:

% kubectl get pods -A | grep coredns
kube-system     coredns-588d4c64bf-t7xkv  1/1   Running   0   314d
kube-system     coredns-588d4c64bf-tfxkz  1/1   Running   0   314d


View CoreDNS logs:

kubectl logs -n kube-system -l k8s-app=kube-dns


Edit CoreDNS config:

kubectl -n kube-system edit configmap coredns



How to prevent disruption of CoreDNS service during node group rolling updates?


Check on which nodes CoreDNS pods are running:

% kubectl get pods -A -o wide  | grep coredns
kube-system    coredns-xxx-yyy   1/1  Running   0  1d   10.1.3.51    ip-10-1-2-123.us-east-1.compute.internal
kube-system    coredns-xxx-yyy   1/1  Running   0  1d   10.1.3.98    ip-10-1-2-123.us-east-1.compute.internal

In this case both pods are on the same node. 

Check CoreDNS pod disruption budget:

% kubectl get pdb -A | grep -E "NAMESPACE|coredns"
NAMESPACE    NAME     MIN AVAILABLE  MAX UNAVAILABLE  ALLOWED DISRUPTIONS   AGE
kube-system  coredns  N/A            1                1                     1d


MAX UNAVAILABLE = 1  is perfect for high availability. As long as we have at least 2 replicas  running, the rolling update will cycle through them safely without losing DNS resolution.

Update Strategy: Check your update_config in Terraform for that node group. If max_unavailable is set to more than 1 (default value is 1), EKS might try to terminate multiple nodes at once, but your PDB will block it, potentially causing a conflict or a very slow update. In that case we can first set it to 1 before we the update.

Resource Headroom: If we are using a Managed Node Group, AWS will usually bring up a new node first (surge) before draining an old one. Ensure our AWS account limits and VPC subnets have enough free IP addresses to accommodate these extra temporary nodes.
---

Monday, 8 July 2024

Google Cloud DNS and Cloud CDN

 


DNS (Domain Name Service) is what translates internet hostnames to addresses.

8.8.8.8 is a free Google public DNS.


Cloud DNS
  • DNS service for internet hostnames and addresses of applications built in Google Cloud
  • managed DNS service (like AWS Route53)
  • runs on the same infrastructure as Google
  • has low latency
  • high availability
  • cost-effective way to make our applications and services available to our users
  • DNS information we publish is served from redundant locations around the world
  • programmable: we can publish and manage millions of DNS zones and records using the Cloud Console, the command-line interface, or the API. 


Edge caching refers to the use of caching servers to store content closer to end users. 


Cloud CDN

  • Google's global system of edge caches (like Amazon CloudFront)
  • Used to accelerate content delivery in our application
    • our customers will experience lower network latency
    • the origins of our content will experience reduced load
  • can be enabled with a single checkbox, after HTTP(S) Load Balancing is set up

Some other CDNs are part of Google Cloud’s CDN Interconnect partner program, and we can continue to use it.

Friday, 28 June 2024

How to fix Docker container not resolving domain names




I had a case where I run a Terraform Docker container but it would fail to reach a provider package repository.

docker-compose.yaml:

---
name: terraform

services:
  terraform:
    image:  hashicorp/terraform:latest
    volumes:
      - .:/infra
    working_dir: /infra

I wanted to execute (terraform) init command (terraform argument here refers to the name of the service, not the terraform executable itself):

$ docker compose run --rm terraform init
[+] Creating 1/1
 ✔ Network import_demo_default  Created                                                                                                                                          0.1s 
[+] Running 5/5
 ✔ terraform Pulled                                                                                                                                                             11.2s 
   ✔ ec99f8b99825 Pull complete                                                                                                                                                  4.2s 
   ✔ 47bfda048af5 Pull complete                                                                                                                                                  8.4s 
   ✔ 755b9030e6bd Pull complete                                                                                                                                                  8.4s 
   ✔ db586b81a2dc Pull complete                                                                                                                                                  9.4s 
Initializing the backend...
Initializing provider plugins...
- Finding kreuzwerker/docker versions matching "3.0.2"...
│ Error: Failed to query available provider packages
│ 
│ Could not retrieve the list of available versions for provider kreuzwerker/docker: could not connect to registry.terraform.io: failed to request discovery document: Get
│ "https://registry.terraform.io/.well-known/terraform.json": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)

I changed entrypoint in order to execute debugging tools. With either

entrypoint: ["wget", "https://registry.terraform.io/.well-known/terraform.json"]

or

entrypoint: ["ping", "registry.terraform.io"]


$ docker compose run --rm terraform

returned:

bad address 'registry.terraform.io'

...and

entrypoint: ["nslookup", "registry.terraform.io"]

returned:

 ;; connection timed out; no servers could be reached


To check the DNS servers used I set entrypoint to print the resolv.conf file:

entrypoint: ["cat", "/etc/resolv.conf"]

This returned:

# Generated by Docker Engine.
# This file can be edited; Docker Engine will not make further changes once it
# has been modified.

nameserver 127.0.0.11
search bigcorp.com
options edns0 trust-ad ndots:0

# Based on host file: '/etc/resolv.conf' (internal resolver)
# ExtServers: [10.10.1.255 10.11.5.183]
# Overrides: [nameservers search]
# Option ndots from: internal


By default, Docker provides a DNS server (daemon's embedded DNS resolver) at 127.0. 0.11, so all DNS requests from containers come to it. Daemon then forwards these requests to uplink DNS servers as defined via --dns arguments, /etc/docker/daemon.json or host's  /etc/resolv.conf.

Containers use the same DNS servers as the host by default, but you can override this with --dns.

By default, containers inherit the DNS settings as defined in the /etc/resolv.conf configuration file. Containers that attach to the default bridge network receive a copy of this file. Containers that attach to a custom network use Docker's embedded DNS server. The embedded DNS server forwards external DNS lookups to the DNS servers configured on the host.
Using --dns is the same as adding dns attribute to /etc/docker/daemon.json. Same applies for --dns-search. DNS settings in /etc/docker/daemon.json will override those set in the local /etc/resolv.conf file.

My local /etc/resolv.conf file:

$ cat /etc/resolv.conf
# This is /run/systemd/resolve/stub-resolv.conf managed by man:systemd-resolved(8).
# Do not edit.
#
# This file might be symlinked as /etc/resolv.conf. If you're looking at
# /etc/resolv.conf and seeing this text, you have followed the symlink.
#
# This is a dynamic resolv.conf file for connecting local clients to the
# internal DNS stub resolver of systemd-resolved. This file lists all
# configured search domains.
#
# Run "resolvectl status" to see details about the uplink DNS servers
# currently in use.
#
# Third party programs should typically not access this file directly, but only
# through the symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a
# different way, replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.

nameserver 127.0.0.53
options edns0 trust-ad
search Home

In my case, uplink DNS server is my local router:

$ resolvectl status
Global
       Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub

Link 2 (enp0s31f6)
Current Scopes: none
     Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported

Link 3 (wlp2s0)
    Current Scopes: DNS
         Protocols: +DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
Current DNS Server: xxxx:a25c:xxxx:0:xxxx:7aff:fe4d:3700
       DNS Servers: 192.168.0.1 xxxx:a25c:xxxx:0:xxxx:7aff:fe4d:3700
        DNS Domain: Home

Link 4 (br-a7ba833104f5)
Current Scopes: none
     Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported

Link 5 (br-d39e3c16b90f)
Current Scopes: none
     Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported

Link 6 (docker0)
Current Scopes: none
     Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported

Link 7 (br-1d4f7fd2e5cc)
Current Scopes: none
     Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported

Link 8 (br-3c8c9487a095)
Current Scopes: none
     Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported

Link 9 (br-7bfedc7c4369)
Current Scopes: none
     Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported

Link 26 (veth846e490)
Current Scopes: none
     Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported

Link 27 (br-c06da6a5a65a)
Current Scopes: none
     Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported

Link 30 (br-c1e0d2aed078)
Current Scopes: none
     Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported

Link 71 (enxa44cc8e41d0f)
Current Scopes: none
     Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported


I discovered that I had DNS settings set in /etc/docker/daemon.json:

$ cat /etc/docker/daemon.json
{
  "dns": ["10.10.1.255", "10.11.5.183"],
  "dns-search": ["bigcorp.com"]
}

As there is no need to use these custom (corporate) DNS servers, I can remove these settings (basically empty) /etc/docker/daemon.json. 

To reload the new (empty) config, I had to flush changes and restart Docker:

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker


Let's check how container's /etc/resolv.conf changed:

$ docker compose run --rm terraform
# Generated by Docker Engine.
# This file can be edited; Docker Engine will not make further changes once it
# has been modified.

nameserver 127.0.0.11
search Home
options edns0 trust-ad ndots:0

# Based on host file: '/etc/resolv.conf' (internal resolver)
# ExtServers: [host(127.0.0.53)]
# Overrides: []
# Option ndots from: internal

Switching entrypoint to nslookup:

entrypoint: ["nslookup", "registry.terraform.io"]

...gives now the expected result:

$ docker compose run --rm terraform
Server:         127.0.0.11
Address:        127.0.0.11:53

Non-authoritative answer:
registry.terraform.io   canonical name = d3rdzqodp6w8cx.cloudfront.net
Name:   d3rdzqodp6w8cx.cloudfront.net
Address: 2600:9000:225d:ee00:16:1aa3:1440:93a1
Name:   d3rdzqodp6w8cx.cloudfront.net
Address: 2600:9000:225d:7c00:16:1aa3:1440:93a1
Name:   d3rdzqodp6w8cx.cloudfront.net
Address: 2600:9000:225d:4a00:16:1aa3:1440:93a1
Name:   d3rdzqodp6w8cx.cloudfront.net
Address: 2600:9000:225d:4800:16:1aa3:1440:93a1
Name:   d3rdzqodp6w8cx.cloudfront.net
Address: 2600:9000:225d:8200:16:1aa3:1440:93a1
Name:   d3rdzqodp6w8cx.cloudfront.net
Address: 2600:9000:225d:7200:16:1aa3:1440:93a1
Name:   d3rdzqodp6w8cx.cloudfront.net
Address: 2600:9000:225d:2000:16:1aa3:1440:93a1
Name:   d3rdzqodp6w8cx.cloudfront.net
Address: 2600:9000:225d:e000:16:1aa3:1440:93a1

Non-authoritative answer:
registry.terraform.io   canonical name = d3rdzqodp6w8cx.cloudfront.net
Name:   d3rdzqodp6w8cx.cloudfront.net
Address: 143.204.68.98
Name:   d3rdzqodp6w8cx.cloudfront.net
Address: 143.204.68.95
Name:   d3rdzqodp6w8cx.cloudfront.net
Address: 143.204.68.128
Name:   d3rdzqodp6w8cx.cloudfront.net
Address: 143.204.68.94

Finally, after removing entrypoint alltogether:

$ docker compose run --rm terraform init
Initializing the backend...
Initializing provider plugins...
- Finding kreuzwerker/docker versions matching "3.0.2"...
- Installing kreuzwerker/docker v3.0.2...
- Installed kreuzwerker/docker v3.0.2 (self-signed, key ID BD080C4571C6104C)
Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

In case there were issues with any of the further uplink DNS resolvers (DNS setting on my local router, DNS issues with my Internet provider etc...) I would try using Google DNS servers directly:

$ cat /etc/docker/daemon.json
{
  "dns": ["8.8.4.4", "8.8.8.8"],
}


But for now I can keep that config file empty.


References:

Thursday, 22 February 2024

Introduction to AWS CloudFront


 

What is AWS CloudFront?

  • Content delivery network (CDN) provided by AWS

Why to use it?

  • To speed up delivery of web content (dynamic, static, streaming, interactive)
  • Content is distributed with low latency and high data transfer speeds

How does it work?

  • Files are delivered to end-users using a global network of edge locations
  • Users who request web content are automatically routed to the edge location that gives them the lowest latency.

How to set it for selected content?

  • Create a distribution and specify settings for it
    • Amazon S3 bucket or HTTP server that we want CloudFront to get the content from
    • whether we want only selected users to have access to that content
    • whether we want users to use HTTPS
    • Alternate domain name (CNAME). This optional setting is a custom domain name that we use in URLs for the files served by this distribution. Example: my-content.example.com.
  • CloudFront then assigns a domain name to the distribution (e.g. abcdef0123456.cloudfront.net) but it's possible to use custom domain name (e.g. example.com)
  • We can now access our resource via URL:
    • http://abcdef0123456.cloudfront.net/index.html or
    • http://example.com/index.html
  • ...
CloudFront >> Distributions are not region-specific, they are global.

Thursday, 16 February 2023

DNS (Domain Name System)

 

  
 

DNS (Domain Name System)

  • a protocol, part of the Internet Protocol (IP) Suite
  • hierarchical and distributed naming system for computers, services, and other resources in the Internet
  • naming database in which internet domain names are located and translated into Internet Protocol (IP) addresses 
  • translates domain names to IP addresses so browsers can load Internet resources
  • helps Internet users and network devices discover websites using human-readable host names, instead of numeric IP addresses; For humans, domain names are a lot easier to remember than a sequence of numbers.
  • DNS configuration settings of some website are what allows visitors to still access that website even after it gets moved to a new hosting provider (its IP address will change but domain name will not)
 
For a hosted web site we need to specify (usually 2) DNS servers. These could be provided by hosting provider but we can specify custom ones e.g. Cloudflare DNS servers. These DNS servers will be nodes in DNS distributed database system which will be providing DNS records about our domains for whoever queries about them. Let's see which DNS records we can set.

Common DNS Records

  • A (A record, Address record,  IPv4 address record)
    • maps from an IPv4 address to a domain name
    • used to point the domain name at one or multiple IP addresses
    • also referred to as a host or hostname
  • AAAA (IPv6 address record) maps domain name to IPv6 address
  • CNAME (Canonical Name record)
    • used to create an alias from one hostname to another
    • maps one domain name (an alias) to another (the canonical name)
    • Example: example.com has an A record which points to the IP address. If we say "www.example.com is a CNAME to example.com" and "ftp.example.com is a CNAME to example.com" that means that someone accessing www.example.com or ftp.example.com will be pointed to the same IP address that example.com points to. This is useful so that when your IP address changes, you only have to update example.com’s entry (DNS A record for example.com), and www.example.com and ftp.example.com automatically point to the right place.
    • If you already have an A record, you will not use a CNAME
    • CNAME record tells anyone visiting a subdomain to also use the same DNS records as another domain or subdomain. 
    • This sort of thing is convenient when running multiple services from a single IP address (e.g. FTP server and web server share the same IP address but different port)
    • CNAME records only work for subdomains and must always point to another domain or subdomain and never directly to an IP address.
    • When a DNS resolver encounters a CNAME record while looking for a regular resource record, it will restart the query using the canonical name instead of the original name.
  • MX (Mail eXchanger)
    • allows you to control the delivery of mail for a given domain or subdomain. In our context, MX records can be set on a host-by-host basis to point to other hosts on the Internet (usually with permanent connections) that are set up to accept and/or route mail for your hostname(s). Setting a backup MX makes the entry you specify a secondary mail exchanger. This means that delivery will be attempted to your host first, and then to the backup host you specify if that fails.
  • TXT (TXT records) 
    • used to store information. Common uses include SPF, DKIM, etc.



CNAME vs A name

An A record points a hostname directly to an IP address, while a CNAME record points a hostname to another hostname.

Think of an A record like a physical street address, and a CNAME record like a nickname or a forwarding address. They are both parts of the Domain Name System (DNS), which acts like the internet's phonebook to help computers find websites.

Quick Comparison


Feature                 A Record (Address)                  CNAME Record (Canonical Name)
What it points to   An IP address (e.g., 192.0.2.1)    Another domain name (e.g., ://shopify.com)
Best used for        The main root domain                  Subdomains and third-party services 
                             (e.g., yourdomain.com)                (e.g., ://yourdomain.com)
Speed                   Faster (resolves in one step)         Slower (requires multiple lookup steps)
Coexistence         Can live with MX, TXT, and       Cannot share a name with any other records
                             other records

The A Record: The Direct Map


The "A" stands for Address. This is the most basic type of DNS record. It connects a name you can type (like a website) straight to the unique number of the computer hosting that site.
  • The Analogy: You look up "The Central Library" in a phone book, and it gives you the exact physical location: 123 Main Street.
  • Real-world Example: You want your root domain mywebsite.com to open your web server. You create an A record pointing to your server's IP address.
    • Name: mywebsite.com
    • Type: A
    • Value: 192.0.2.23

The CNAME Record: The Alias


"CNAME" stands for Canonical Name. Instead of pointing to a number, it points to another name. It tells the computer, "Hey, I don't have the IP address, go look at this other website name to find it!"
  • The Analogy: You look up "The City Book Place" in the phone book. The book says, "This is just another name for The Central Library. Go look up The Central Library instead."
  • Real-world Example: You build an online shop using a service like Shopify. Shopify gives you a unique store address like ://myshopify.com. You want customers to see ://mywebsite.com instead. You create a CNAME record:
    • Name: ://mywebsite.com
    • Type: CNAME
    • Value: ://myshopify.com


Example Scenario: What Happens Behind the Scenes?

Imagine a user types ://mywebsite.com into their browser. Here is how the internet figures out where to go using both records:
  1. The CNAME Step: The computer asks the DNS server for the location of ://mywebsite.com. The server replies: "That name is just an alias for ://myshopify.com."
  2. The A Record Step: The computer then asks the DNS server: "Okay, what is the address for ://myshopify.com?"
  3. The Final Destination: Shopify’s DNS server looks at its own A record and replies: "The IP address is 23.227.38.65."
  4. The website opens!

Why use a CNAME instead of an A Record?


If Shopify ever changes its server IP addresses, they only have to update their own A record. Because your CNAME points to their name and not their number, your shop keeps working perfectly without you changing a thing.


Can CNAME coexist with A name?


In the Domain Name System (DNS), a CNAME (Canonical Name) record cannot coexist with other DNS records that share the exact same hostname (Name).

Because a CNAME acts as a pointer or alias for another domain, it overrides all other records for that specific name. Standard DNS specifications explicitly prohibit mixing a CNAME with A, AAAA, MX, TXT, or NS records for the same host.

The Exceptions to the Rule


There are only two scenarios where a CNAME can be used alongside other data at the same name:
  • DNSSEC: If your domain uses DNS security, cryptographic records (like RRSIG and NSEC) must exist alongside the CNAME.
  • "CNAME-like" proprietary records: Many DNS providers (like DNSimple, Cloudflare, and others) offer custom ALIAS or ANAME records. These synthetic records allow you to alias a domain while still hosting other records like MX records for email alongside them.

Common DNS Conflicts


If you try to add a CNAME, you will usually get an error from your DNS provider if you already have these records for the same name:
A or AAAA records: CNAMEs cannot map to an IP address directly, so they conflict with address records.
MX records: If you need a CNAME for a web service, but also need MX records for email, you cannot put both on the same subdomain (e.g., you cannot have ://yourdomain.com be both a CNAME and an MX record).
TXT records: You cannot verify a domain with a TXT record if the hostname already has a CNAME.


How to Fix Coexistence Issues


If you need both types of records for the same purpose, consider these common workarounds:
  • Use subdomains: You can create a CNAME on ://yourdomain.com and use your main yourdomain.com for your MX/TXT records.
  • Use ALIAS/ANAME records: If your host allows it, switch to an ALIAS/ANAME record for the zone apex (the root domain) so that you can simultaneously maintain MX records for email.
  • Use A/AAAA records: Instead of creating a CNAME, simply resolve the target domain to its IP address and create standard A/AAAA records, which can coexist with TXT or MX records.


DNS records for bojankomazec.com, my domain registered with GoDaddy:

========================================================= 
Type   Name  Data               TTL    Delete     Edit
========================================================= 
A @ 216.58.213.115         600 seconds
NS @ ns31.domaincontrol.com. 1 Hour Can't delete Can't edit
NS @ ns32.domaincontrol.com. 1 Hour Can't delete Can't edit
CNAME email email.secureserver.net. 1 Hour
CNAME ftp bojankomazec.com. 1 Hour
CNAME ihXXXXXXXX6i gv-7sXXXXXXXXv3xr.dv.googlehosted.com. 1 Hour
CNAME www ghs.google.com.                                 1 Hour
CNAME _domainconnect _domainconnect.gd.domaincontrol.com. 1 Hour
SOA @ Primary nameserver: ns31.domaincontrol.com.    600 secs
MX @ smtp.secureserver.net. (Priority: 0)         1 Hour
MX @ mailstore1.secureserver.net. (Priority: 10) 1 Hour
========================================================= 

CNAME records in blue are those that I had manually to set so that my bojan-komazec.blogspot.com gets redirected to bojankomazec.com. See Set up a custom domain - Blogger Help. Also, look at https://www.nslookup.io/domains/bojankomazec.com/webservers/.

Linux offers a DNS lookup tool which can be used to find out the nameservers and e.g. IP address of the domain:

$ host -t ns bojankomazec.com
bojankomazec.com name server ns31.domaincontrol.com.
bojankomazec.com name server ns32.domaincontrol.com.

$ host bojankomazec.com

bojankomazec.com has address 216.58.213.115
bojankomazec.com mail is handled by 10 mailstore1.secureserver.net.
bojankomazec.com mail is handled by 0 smtp.secureserver.net.



It can take up to 72 hours for setting new DNS records to take effect - while change is replicated across all DNS servers on the internet. (see DNS Propagation)
 
The network of DNS servers is hierarchical. Types of DNS servers are:
  • Recursive resolvers (DNS recursors)
    • clients first send to them DNS queries
    • they are assigned by ISP but can be set manually:
      • Cloudflare 1.1.1.1
      • Google (8.8.8.8 and 8.8.4.4)
    • they respond either with cached data or send the request to root, TDL and finally to Authoritative nameserver from which they receive IP address
    • every recursive resolver knows about 13 (types of) DNS root nameservers
  • Root nameservers
    • when receive query about some domain name e.g. example.com they return the address of the TLD nameserver which contains information about the domain extension e.g. .com 
    • there are over 600 root nameservers which sync among themselves (anycast routing) and all contain the same data
  • TLD (Top-Level Domain) nameservers
    • they are domain extension-specific - each of them contains the list of authoritative servers for only a single domain e.g. .com or .ai. 
    • they return the address of authoritative servers
    • Larger TLDs and registrars (like GoDaddy, Namcheap etc...) use an API call to notify the TLD operator of any new registrations and changes
  • Authoritative nameserver
    • resolver’s last step in the journey for an IP address
    • they are domain-specific - each of them contains the list of IP addresses for a particular doman e.g. ftp.example.com or www.example.com
    • they return the IP address for a given hostname or, if domain has a CNAME (alias domain name), resolver needs to repeat the whole process in order to get the IP address for that alias host name.
    • when you register your web site, name servers you set for it are authoritative nameservers
 

To manage DNS records of domain e.g. example.com means setting DNS records for its root and subdomains. For each record we set:
  • Type: A, CNAME, MX, ...
  • Name: e.g. ftp (for ftp.example.com)
  • Content: this is the value which depends on the type e.g. IPv4 address if A record, alias if CNAME etc....
  • Proxy status: DNS only (proxy disabled) or Proxied (proxy enabled)
  • TTL (Time to Live) - in minutes


NS Records


NS records (short for Name Server records) are a fundamental part of the Domain Name System (DNS). They tell the rest of the internet which DNS servers are the authoritative bosses for your domain.

In plain English: when someone types your website address into a browser, the NS records point them to the exact servers that hold the map (the IP addresses) for that domain.

How They Work (The Mailroom Analogy)


Think of the DNS process like looking up a physical business address:

  1. The Request: A user types example.com.
  2. The Registrar: The internet checks the global registry (like .com) to see where example.com is registered.
  3. The NS Record: The registry looks at your domain's NS records and says, "Go talk to ns1.nameserver.com—they have the official records for this site."
  4. The Resolution: The browser asks that specific name server for the actual website IP address (via an A record), and the site loads.

Crucial Rule: Without NS records, your domain is effectively lost. The internet will know you own the name, but it won't know which server to ask for directions to get there.

Why Do You Usually See Two or More?


You will almost never see just one NS record for a domain. They always come in clusters—usually at least two, sometimes four:

  • ns1.provider.com
  • ns2.provider.com

This is entirely for redundancy. If one name server goes down due to a hardware failure or a cyberattack, the other servers are there to instantly pick up the slack so your website, email, and cloud services don't go offline.

Changing NS Records


You typically edit NS records at your domain registrar (the place where you bought the domain).

You usually only change them when you are switching your DNS management to a new provider. For example, if you buy a domain at one company but want to route and protect your web traffic through a cloud platform like Cloudflare, you will replace the original registrar's NS records with Cloudflare's name servers.

Once you update them, it can take anywhere from a few minutes up to 48 hours for routers across the globe to learn the new directions—a period known as DNS propagation.



Resources: