{
    "version": "https:\/\/jsonfeed.org\/version\/1.1",
    "title": "Blog — George Mishurovsky: posts tagged linux",
    "_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\/linux\/",
    "feed_url": "https:\/\/mishurovsky.com\/blog\/?go=tags%2Flinux%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": "50",
            "url": "https:\/\/mishurovsky.com\/blog\/?go=all\/jq-is-wonderful\/",
            "title": "<span class=\"inline-code\">jq<\/span> is Wonderful!",
            "content_html": "<div class=\"e2-text-picture\">\n<img src=\"https:\/\/mishurovsky.com\/blog\/pictures\/jq-is-wonderful@2x.jpg\" width=\"924\" height=\"327\" alt=\"\" \/>\n<\/div>\n<p>Linux is a brilliant OS — because it has a great set of tools to work with text files! Today I’ve tried to use <span class=\"inline-code\">jq<\/span> to come up with a little wonder I find worth sharing. Might be it will make your life simpler too.<\/p>\n<p>Suppose you have a <span class=\"inline-code\">chat-export.json<\/span> with your monthly spendings mixed with other messages like this:<\/p>\n<div class=\"e2-code-block\" data-language=\"json\"><div class=\"e2-code-header\"><span class=\"e2-code-language\">JSON<\/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-json\">[\n  {\n    &quot;id&quot;: 139,\n    &quot;message&quot;: &quot;18 pizza in Pizza World&quot;,\n    &quot;chat&quot;: {\n      &quot;id&quot;: 123,\n    },\n    &quot;date&quot;: &quot;2026-02-26 10:15:00+00:00&quot;\n    \/\/ ...30 fields more\n  },\n  {\n    &quot;id&quot;: 140,\n    &quot;message&quot;: &quot;120 bills&quot;,\n    &quot;chat&quot;: {\n      &quot;id&quot;: 123,\n    },\n    &quot;date&quot;: &quot;2026-03-02 14:30:00+00:00&quot;\n  },\n  {\n    &quot;id&quot;: 141,\n    &quot;message&quot;: &quot;Some message from another chat&quot;,\n    &quot;chat&quot;: {\n      &quot;id&quot;: 140,\n    },\n    &quot;date&quot;: &quot;2026-03-02 19:20:00+00:00&quot;\n  },\n  {\n    &quot;id&quot;: 142,\n    &quot;message&quot;: &quot;3.5 coffee in Cream&quot;,\n    &quot;chat&quot;: {\n      &quot;id&quot;: 123,\n    },\n    &quot;date&quot;: &quot;2026-03-08 08:45:00+00:00&quot;\n  },\n  {\n    &quot;id&quot;: 143,\n    &quot;message&quot;: &quot;Another unrelated message&quot;,\n    &quot;chat&quot;: {\n      &quot;id&quot;: 156,\n    },\n    &quot;date&quot;: &quot;2026-03-11 12:05:00+00:00&quot;\n  },\n  \/\/ ...1000 entries more\n]<\/code><\/pre><\/div><p>How can you calculate your spendings in March *fast*? <span class=\"inline-code\">jq<\/span> to the rescue!<\/p>\n<div class=\"e2-code-block\" data-language=\"sh\"><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-sh\">jq &#039;[ .[]                       # iterate over array items\n  | select(.chat.id == 123)     # filter the ones from budget chat\n  | select(.date | startswith(&quot;2026-03&quot;)) # filter the ones from March\n  | .message                    # extract message text\n  | gsub(&quot;[^0-9.]&quot;; &quot;&quot;)         # leave only numeric symbols and dots\n  | tonumber                    # convert text to numbers\n] | add&#039; chat-export.json       # get the sum!<\/code><\/pre><\/div><p>Or as a one-liner:<\/p>\n<div class=\"e2-code-block\" data-language=\"shell\" data-long><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\">jq &#039;[ .[] | select(.chat.id == 123) | select(.date | startswith(&quot;2026-03&quot;)) | .message | gsub(&quot;[^0-9.]&quot;; &quot;&quot;) | tonumber ] | add&#039; chat-export.json<\/code><\/pre><\/div><p>As short as it can get, clear, easy to use — and no software involved apart from utilities that come with the system. Shiny! ✨<\/p>\n",
            "date_published": "2026-03-30T11:05:29+02:00",
            "date_modified": "2026-03-30T11:05:16+02:00",
            "tags": [
                "data analytics",
                "jq",
                "linux",
                "shell"
            ],
            "image": "https:\/\/mishurovsky.com\/blog\/pictures\/jq-is-wonderful@2x.jpg",
            "_date_published_rfc2822": "Mon, 30 Mar 2026 11:05:29 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "50",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": [
                    "https:\/\/mishurovsky.com\/blog\/pictures\/jq-is-wonderful@2x.jpg"
                ]
            }
        },
        {
            "id": "5",
            "url": "https:\/\/mishurovsky.com\/blog\/?go=all\/how-to-quickly-retrieve-past-terminal-commands\/",
            "title": "How to View Past Terminal Commands — from Simple to Robust",
            "content_html": "<p>Suppose you want to re-run some shell command you used ten days ago. It is a complex one; you do not remember exact flags and argument values, and it would take a long time to recall an exact text. What can you do?<\/p>\n<h2>1. The upwards arrow<\/h2>\n<p>Majority of devs working with command line knows it. Press “up” to see a previous command, press “down” for a next command, press “Ctrl+C” to drop whatever is in the prompt and start fresh.<\/p>\n<p>This approach works, but gets very tedious when you need to find a command you used last week or last month. Once more than ten or twenty commands have passed, scrolling through them becomes tedious.<\/p>\n<h2>2. Terminal history file<\/h2>\n<p>All the commands you enter into a terminal get stored in <span class=\"inline-code\">.bash_history<\/span> file (or <span class=\"inline-code\">.zsh_history<\/span> if you are on Mac) up to a certain limit. Thus, you can run:<\/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\">cat ~\/.bash_history # output all into the terminal\nless ~\/.bash_history # or use any text viewer\ntail -n 20 ~\/.bash_history # or observe only the most recent n lines\ncat ~\/.bash_history | grep whatever # to search for specific patterns<\/code><\/pre><\/div><p>This method gives you full access to your history file, and lets you search more flexibly.<\/p>\n<h2>3. <span class=\"inline-code\">history<\/span> command<\/h2>\n<p>Almost the same as using the history file directly: you get a list commands, but now it is <i>numbered<\/i>.<\/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\">history -20 # show the last 20 commands\nhistory -500 | grep ssh # search for a specific patter in a command\n!780 # execute command with order number 780<\/code><\/pre><\/div><p>But there is one important difference from direct usage of <span class=\"inline-code\">.bash_history<\/span>:<\/p>\n<ul>\n<li><span class=\"inline-code\">history<\/span> command uses the last <span class=\"inline-code\">HISTSIZE<\/span> history entries (default 1000)<\/li>\n<li><span class=\"inline-code\">.bash_history<\/span> file uses the last <span class=\"inline-code\">HISTFILESIZE<\/span> entries (default 2000)<br \/>\nSo, if your command was run a really long time ago, <span class=\"inline-code\">history<\/span> may not find it, but direct inspection of <span class=\"inline-code\">.bash_history<\/span> can do.<\/li>\n<\/ul>\n<h2>4. <span class=\"inline-code\">fc -l<\/span> command<\/h2>\n<p>This command behaves very similar to <span class=\"inline-code\">history<\/span>, with an additional ability to display ranges of command numbers::<\/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\">fc -l -20 # show the last 20 commands\nfc -l 100 150 # show commands 100 to 150<\/code><\/pre><\/div><h2>5. Reverse-i-search<\/h2>\n<p>This is the most powerful approach. Press “Ctrl+R” to enter reverse incremental search mode. Initially you get no output; start writing any part of a command you remember, e. g. <span class=\"inline-code\">ssh<\/span> or <span class=\"inline-code\">input.json<\/span> or <span class=\"inline-code\">-n 10<\/span> — and you will see the first full command entry with that match!<\/p>\n<p>From there, you can:<\/p>\n<ul>\n<li>Press “Enter” to execute the command immediately<\/li>\n<li>Use left\/right arrow keys to move within a command to edit it, then press “Enter” to execute<\/li>\n<li>Press “Ctrl+R” again to go to the next, older match<\/li>\n<li>Press “Ctrl+S” to go to the previous, newer match (see comment below)<\/li>\n<li>Press up-down arrows to view to nearby entries in history around the match<\/li>\n<li>Press “Ctrl+C” or “Ctrl+G” to exit the search<\/li>\n<\/ul>\n<p>On many systems “Ctrl+S” shortcut will not work, as it is prioritized to pause terminal output (press “Ctrl+Q” to resume). To make it work for reverse-i-search, add <span class=\"inline-code\">stty -ixon<\/span> to your shell config. It will disable “Ctrl+S” \/ “Ctrl+Q” shortcuts for terminal flow control:<\/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\">echo &quot;stty -ixon&quot; &gt;&gt; ~\/.bashrc\nsource ~\/.bashrc<\/code><\/pre><\/div><p>Happy command line manipulation!<\/p>\n<p>💡 This post has a second part: <a href=\"https:\/\/mishurovsky.com\/blog\/all\/shell-configs-for-better-command-history-search\/\">Shell Configs for Better Command History Search<\/a><\/p>\n",
            "date_published": "2025-08-03T14:18:24+02:00",
            "date_modified": "2025-10-21T11:41:00+02:00",
            "tags": [
                "devops",
                "guides",
                "linux",
                "mac",
                "search",
                "shell",
                "terminal"
            ],
            "_date_published_rfc2822": "Sun, 03 Aug 2025 14:18:24 +0200",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "5",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": []
            }
        },
        {
            "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)"
}