{
    "version": "https:\/\/jsonfeed.org\/version\/1.1",
    "title": "Blog — George Mishurovsky: posts tagged ubuntu",
    "_rss_description": "A blog by George Mishurovsky — a senior software engineer with a medical degree. Drawing from both engineering and scientific thinking, he explores software, architecture, design, psychology, and product thinking.",
    "_rss_language": "en",
    "_itunes_email": "george@mishurovsky.com",
    "_itunes_categories_xml": "",
    "_itunes_image": "https:\/\/mishurovsky.com\/blog\/pictures\/userpic\/userpic-square@2x.jpg?1753619610",
    "_itunes_explicit": "no",
    "home_page_url": "https:\/\/mishurovsky.com\/blog\/?go=tags\/ubuntu\/",
    "feed_url": "https:\/\/mishurovsky.com\/blog\/?go=tags%2Fubuntu%2Fjson%2F",
    "icon": "https:\/\/mishurovsky.com\/blog\/pictures\/userpic\/userpic@2x.jpg?1753619610",
    "authors": [
        {
            "name": "George Mishurovsky",
            "url": "https:\/\/mishurovsky.com\/blog\/",
            "avatar": "https:\/\/mishurovsky.com\/blog\/pictures\/userpic\/userpic@2x.jpg?1753619610"
        }
    ],
    "items": [
        {
            "id": "1",
            "url": "https:\/\/mishurovsky.com\/blog\/?go=all\/diagnosing-dns-and-redirection-issues-ubuntu-apache-letsencrypt\/",
            "title": "Useful Commands to Debug DNS Issues and Redirection Loops (Ubuntu, Apache, Letsencrypt)",
            "content_html": "<p>Recently I decided to add a blog to my personal website. Now I can regularly share thoughts with everyone! The blog resides at <a href=\"https:\/\/mishurovsky.com\/blog\/,\">https:\/\/mishurovsky.com\/blog\/,<\/a> while the main page remains at <a href=\"https:\/\/mishurovsky.com.\">https:\/\/mishurovsky.com.<\/a><\/p>\n<p>The path to a working solution, however, was not easy. My website is a Next.js application hosted on Vercel, while the blog engine I chose is a PHP application requiring a separate Linux server with Apache and MariaDB. My initial intent was to lead all traffic through a self-hosted reverse proxy, which would direct \/blog requests to the blog engine, and all other requests to the Vercel page. I did not manage to make it work, so I ended up hosting both PHP and Next.js apps from my own server.<\/p>\n<p>But that wasn’t the end of the story. After migration, HTTP connection was OK, but whenever I tried to switch to HTTPS, the response was still served by Vercel, even though I deleted both my domain and project from there! It was not just a failing request, but a redirection loop, 308 to mishurovsky.com again and again and again. I spent two days debugging configs and waiting for DNS caches to clear.<\/p>\n<p>Long story short, the problem was in my use of Letsencrypt: I launched it as<\/p>\n<div class=\"e2-code-block\" data-language=\"shell\"><div class=\"e2-code-header\"><span class=\"e2-code-language\">Shell<\/span><button class=\"e2-code-copy\" type=\"button\" aria-label=\"Copy code to clipboard\" data-copy-text=\"Copy\" data-copied-text=\"Copied!\" data-failed-text=\"Failed\"><span class=\"e2-svgi\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 16 16\"><mask id=\"cutout\"><rect width=\"100%\" height=\"100%\" fill=\"white\"\/><rect x=\"1.75\" y=\"5.25\" width=\"9\" height=\"9\" stroke-width=\"1.33\" rx=\"1\" fill=\"black\" stroke=\"black\"\/><\/mask><rect x=\"5.25\" y=\"1.75\" width=\"9\" height=\"9\" rx=\"1\" stroke-width=\"1.33\" fill=\"none\" mask=\"url(#cutout)\"\/><rect x=\"1.75\" y=\"5.25\" width=\"9\" height=\"9\" rx=\"1\" stroke-width=\"1.33\" fill=\"none\"\/><\/svg>\r\n<\/span>Copy<\/button><\/div><pre><code class=\"hljs language-shell\">certbot --apache ...# instead of certbot certonly --apache ...<\/code><\/pre><\/div><p>, and Certbot created a separate HTTPS virtual host that reused an old configuration pointing to Vercel’s upstream. Apache prioritized this config over mine, causing a persistent redirect loop.<\/p>\n<h2>Helpful Commands to Debug DNS Problems and Redirection Loops<\/h2>\n<p>During this weekend journey, I discovered a lot of valuable commands to debug connectivity problems, which I want to share. Hopefully, these will help you, my reader, or me myself in some future.<\/p>\n<h3>1. Verbose cURL<\/h3>\n<div class=\"e2-code-block\" data-language=\"shell\"><div class=\"e2-code-header\"><span class=\"e2-code-language\">Shell<\/span><button class=\"e2-code-copy\" type=\"button\" aria-label=\"Copy code to clipboard\" data-copy-text=\"Copy\" data-copied-text=\"Copied!\" data-failed-text=\"Failed\"><span class=\"e2-svgi\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 16 16\"><mask id=\"cutout\"><rect width=\"100%\" height=\"100%\" fill=\"white\"\/><rect x=\"1.75\" y=\"5.25\" width=\"9\" height=\"9\" stroke-width=\"1.33\" rx=\"1\" fill=\"black\" stroke=\"black\"\/><\/mask><rect x=\"5.25\" y=\"1.75\" width=\"9\" height=\"9\" rx=\"1\" stroke-width=\"1.33\" fill=\"none\" mask=\"url(#cutout)\"\/><rect x=\"1.75\" y=\"5.25\" width=\"9\" height=\"9\" rx=\"1\" stroke-width=\"1.33\" fill=\"none\"\/><\/svg>\r\n<\/span>Copy<\/button><\/div><pre><code class=\"hljs language-shell\">curl -v https:\/\/example.com<\/code><\/pre><\/div><p>Connect to a website and get a <b>verbose<\/b> response. Helps to see HTTP response codes and SSL connectivity status.<\/p>\n<h3>2. cURL with redirects<\/h3>\n<div class=\"e2-code-block\" data-language=\"shell\"><div class=\"e2-code-header\"><span class=\"e2-code-language\">Shell<\/span><button class=\"e2-code-copy\" type=\"button\" aria-label=\"Copy code to clipboard\" data-copy-text=\"Copy\" data-copied-text=\"Copied!\" data-failed-text=\"Failed\"><span class=\"e2-svgi\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 16 16\"><mask id=\"cutout\"><rect width=\"100%\" height=\"100%\" fill=\"white\"\/><rect x=\"1.75\" y=\"5.25\" width=\"9\" height=\"9\" stroke-width=\"1.33\" rx=\"1\" fill=\"black\" stroke=\"black\"\/><\/mask><rect x=\"5.25\" y=\"1.75\" width=\"9\" height=\"9\" rx=\"1\" stroke-width=\"1.33\" fill=\"none\" mask=\"url(#cutout)\"\/><rect x=\"1.75\" y=\"5.25\" width=\"9\" height=\"9\" rx=\"1\" stroke-width=\"1.33\" fill=\"none\"\/><\/svg>\r\n<\/span>Copy<\/button><\/div><pre><code class=\"hljs language-shell\">curl -I -L https:\/\/example.com<\/code><\/pre><\/div><p>Connect to a website and get only <b>headers<\/b> in response + <b>follow redirects<\/b>. I used this countless times to examine if redirect loops persist.<\/p>\n<h3>3. Get site IP<\/h3>\n<div class=\"e2-code-block\" data-language=\"shell\"><div class=\"e2-code-header\"><span class=\"e2-code-language\">Shell<\/span><button class=\"e2-code-copy\" type=\"button\" aria-label=\"Copy code to clipboard\" data-copy-text=\"Copy\" data-copied-text=\"Copied!\" data-failed-text=\"Failed\"><span class=\"e2-svgi\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 16 16\"><mask id=\"cutout\"><rect width=\"100%\" height=\"100%\" fill=\"white\"\/><rect x=\"1.75\" y=\"5.25\" width=\"9\" height=\"9\" stroke-width=\"1.33\" rx=\"1\" fill=\"black\" stroke=\"black\"\/><\/mask><rect x=\"5.25\" y=\"1.75\" width=\"9\" height=\"9\" rx=\"1\" stroke-width=\"1.33\" fill=\"none\" mask=\"url(#cutout)\"\/><rect x=\"1.75\" y=\"5.25\" width=\"9\" height=\"9\" rx=\"1\" stroke-width=\"1.33\" fill=\"none\"\/><\/svg>\r\n<\/span>Copy<\/button><\/div><pre><code class=\"hljs language-shell\">dig +short example.com<\/code><\/pre><\/div><p>Get an ip for a website. Useful when checking if a website is indeed hosted from a rented server.<\/p>\n<h3>4. Show all Letsencrypt certificates<\/h3>\n<div class=\"e2-code-block\" data-language=\"shell\"><div class=\"e2-code-header\"><span class=\"e2-code-language\">Shell<\/span><button class=\"e2-code-copy\" type=\"button\" aria-label=\"Copy code to clipboard\" data-copy-text=\"Copy\" data-copied-text=\"Copied!\" data-failed-text=\"Failed\"><span class=\"e2-svgi\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 16 16\"><mask id=\"cutout\"><rect width=\"100%\" height=\"100%\" fill=\"white\"\/><rect x=\"1.75\" y=\"5.25\" width=\"9\" height=\"9\" stroke-width=\"1.33\" rx=\"1\" fill=\"black\" stroke=\"black\"\/><\/mask><rect x=\"5.25\" y=\"1.75\" width=\"9\" height=\"9\" rx=\"1\" stroke-width=\"1.33\" fill=\"none\" mask=\"url(#cutout)\"\/><rect x=\"1.75\" y=\"5.25\" width=\"9\" height=\"9\" rx=\"1\" stroke-width=\"1.33\" fill=\"none\"\/><\/svg>\r\n<\/span>Copy<\/button><\/div><pre><code class=\"hljs language-shell\">certbot certificates<\/code><\/pre><\/div><p>List all Letsencrypt certificates on a server with their domains, expiration dates, and paths to private and public keys.<\/p>\n<h3>5. Review Apache config<\/h3>\n<div class=\"e2-code-block\" data-language=\"shell\"><div class=\"e2-code-header\"><span class=\"e2-code-language\">Shell<\/span><button class=\"e2-code-copy\" type=\"button\" aria-label=\"Copy code to clipboard\" data-copy-text=\"Copy\" data-copied-text=\"Copied!\" data-failed-text=\"Failed\"><span class=\"e2-svgi\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 16 16\"><mask id=\"cutout\"><rect width=\"100%\" height=\"100%\" fill=\"white\"\/><rect x=\"1.75\" y=\"5.25\" width=\"9\" height=\"9\" stroke-width=\"1.33\" rx=\"1\" fill=\"black\" stroke=\"black\"\/><\/mask><rect x=\"5.25\" y=\"1.75\" width=\"9\" height=\"9\" rx=\"1\" stroke-width=\"1.33\" fill=\"none\" mask=\"url(#cutout)\"\/><rect x=\"1.75\" y=\"5.25\" width=\"9\" height=\"9\" rx=\"1\" stroke-width=\"1.33\" fill=\"none\"\/><\/svg>\r\n<\/span>Copy<\/button><\/div><pre><code class=\"hljs language-shell\">apache2ctl -S<\/code><\/pre><\/div><p>All the main Apache config details: virtual hosts and structure. The most interesting part is error section in the beginning of the output — this is where I found a reference to an additional config from Letsencrypt.<\/p>\n<h3>6. Examine Port Usage<\/h3>\n<div class=\"e2-code-block\" data-language=\"shell\"><div class=\"e2-code-header\"><span class=\"e2-code-language\">Shell<\/span><button class=\"e2-code-copy\" type=\"button\" aria-label=\"Copy code to clipboard\" data-copy-text=\"Copy\" data-copied-text=\"Copied!\" data-failed-text=\"Failed\"><span class=\"e2-svgi\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 16 16\"><mask id=\"cutout\"><rect width=\"100%\" height=\"100%\" fill=\"white\"\/><rect x=\"1.75\" y=\"5.25\" width=\"9\" height=\"9\" stroke-width=\"1.33\" rx=\"1\" fill=\"black\" stroke=\"black\"\/><\/mask><rect x=\"5.25\" y=\"1.75\" width=\"9\" height=\"9\" rx=\"1\" stroke-width=\"1.33\" fill=\"none\" mask=\"url(#cutout)\"\/><rect x=\"1.75\" y=\"5.25\" width=\"9\" height=\"9\" rx=\"1\" stroke-width=\"1.33\" fill=\"none\"\/><\/svg>\r\n<\/span>Copy<\/button><\/div><pre><code class=\"hljs language-shell\">ss -tuln | grep &#039;:443&#039;\nlsof -i :443<\/code><\/pre><\/div><p>List all listening sockets (TCP\/UDP), showing if port 443 is open. Then get a list of all process on port 443 (HTTPS).<\/p>\n<h3>7. Flush DNS Cache<\/h3>\n<p>Finally, Mac OS specific:<\/p>\n<div class=\"e2-code-block\" data-language=\"shell\"><div class=\"e2-code-header\"><span class=\"e2-code-language\">Shell<\/span><button class=\"e2-code-copy\" type=\"button\" aria-label=\"Copy code to clipboard\" data-copy-text=\"Copy\" data-copied-text=\"Copied!\" data-failed-text=\"Failed\"><span class=\"e2-svgi\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 16 16\"><mask id=\"cutout\"><rect width=\"100%\" height=\"100%\" fill=\"white\"\/><rect x=\"1.75\" y=\"5.25\" width=\"9\" height=\"9\" stroke-width=\"1.33\" rx=\"1\" fill=\"black\" stroke=\"black\"\/><\/mask><rect x=\"5.25\" y=\"1.75\" width=\"9\" height=\"9\" rx=\"1\" stroke-width=\"1.33\" fill=\"none\" mask=\"url(#cutout)\"\/><rect x=\"1.75\" y=\"5.25\" width=\"9\" height=\"9\" rx=\"1\" stroke-width=\"1.33\" fill=\"none\"\/><\/svg>\r\n<\/span>Copy<\/button><\/div><pre><code class=\"hljs language-shell\">sudo dscacheutil -flushcache\nsudo killall -HUP mDNSResponder<\/code><\/pre><\/div><p>These two commands flush DNS cache on modern Macs, so DNS could be tested after updates. Requires to quit and re-start a browser after execution.<\/p>\n",
            "date_published": "2025-07-27T20:32:29+02:00",
            "date_modified": "2025-07-29T09:46:18+02:00",
            "tags": [
                "apache",
                "devops",
                "DNS",
                "letsencrypt",
                "linux",
                "ubuntu"
            ],
            "_date_published_rfc2822": "Sun, 27 Jul 2025 20:32:29 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "1",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": []
            }
        }
    ],
    "_e2_version": 4134,
    "_e2_ua_string": "Aegea 11.3 (v4134e)"
}