<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://gowtham.dev/feed.xml" rel="self" type="application/atom+xml" /><link href="https://gowtham.dev/" rel="alternate" type="text/html" /><updated>2026-09-29T06:26:25+00:00</updated><id>https://gowtham.dev/feed.xml</id><title type="html">Gowtham</title><subtitle>rants, learnings and documentations from a 1x engineer.</subtitle><author><name>Gowtham Gopalakrishnan</name></author><entry><title type="html">My server was hacked</title><link href="https://gowtham.dev/blog/my-server-was-hacked.html?ref=rss" rel="alternate" type="text/html" title="My server was hacked" /><published>2026-09-27T14:04:12+00:00</published><updated>2026-09-27T14:04:12+00:00</updated><id>https://gowtham.dev/blog/my-server-was-hacked</id><content type="html" xml:base="https://gowtham.dev/blog/my-server-was-hacked.html"><![CDATA[<p><sub><i>Scroll to the bottom to see TLDR</i></sub></p>

<p>2 days back, on one of my servers I had a CPU high usage alert. It’s a Hetzner box for most of my <a href="/blog/self-hosting-setup-2025.html">self-hosted</a> services managed via Terraform and Ansible<sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup>. I thought it was temporary (<em>big mistake</em>) and since my on-call days were over, I went to bed. I noticed the alerts were still open in the morning flooding my email and personal slack channels.</p>

<p>I opened up the Grafana dashboard and saw this consistent high CPU for more than 12 hours:</p>

<p><img src="/static/img/server-hacked/grafana-high-cpu.png" alt="grafana cpu graph" /></p>

<p>Obviously something was wrong. I <code class="language-plaintext highlighter-rouge">SSH</code>ed to the machine, ran <code class="language-plaintext highlighter-rouge">htop</code> and found the process <code class="language-plaintext highlighter-rouge">syslog-ng</code> taking most of the CPU.</p>

<p><img src="/static/img/server-hacked/htop.png" alt="htop indicating syslog-ng consuming too much CPU" /></p>

<p>Weird and I had no clue why that is. Maybe some logging process was consuming too many CPU cycles? Since I just installed the <code class="language-plaintext highlighter-rouge">gcx</code> some days before and I ran way too many containers, I thought why not hand this over to LLM. I started a pi session with <code class="language-plaintext highlighter-rouge">gpt-6-sol</code>, gave the context to it and it quickly narrowed the high CPU spikes to the plausible container. In less than a minute, it reported the following:</p>

<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The server's CPU spike is dominated by a suspicious process inside the Plausible container. At inspection, the host load was about 20 on 16 cores, and <span class="sb">`syslog-ng-29d93e80`</span> was using roughly 1,500% CPU—about 15 cores.

The process started on September 25 at 18:57 UTC. Its executable ran from a hidden directory under <span class="sb">`/var/tmp`</span>, has since been deleted, and has an established connection to <span class="sb">`141.95.72.61:443`</span>. Those findings are consistent with a compromise, potentially a cryptominer, but I have not confirmed the binary’s purpose. I made no changes to the server.

Treat <span class="sb">`plausible-plausible-1`</span> as potentially compromised. Preserve evidence before stopping or recreating it, then investigate how the process was launched and whether the host or other containers were affected. Separately, <span class="sb">`gcx`</span> could not query historical metrics: its active <span class="sb">`default`</span> context has no Grafana stack configured, despite the earlier login.
</code></pre></div></div>

<p>So, my server had been compromised. <code class="language-plaintext highlighter-rouge">gcx</code> did not work because I had not logged into my self-hosted Grafana instance from my Mac Mini. The agent found the suspicious process after I asked it to investigate the server’s CPU spike over SSH and use <code class="language-plaintext highlighter-rouge">gcx</code> if needed.</p>

<p>I rebooted the server (<em>knee-jerk reaction</em>), logged into <code class="language-plaintext highlighter-rouge">gcx</code> and post reboot I couldn’t see the CPU spiking. I then checked Plausible’s GitHub releases for security updates and found that <a href="https://github.com/plausible/analytics/releases/tag/v3.2.1">v3.2.1</a> was a security release. I was running v3.0.1.</p>

<p>I asked for the evidence of the compromise and the LLM showed the container logs:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>13:27:42  Malware name: syslog-ng-29d93e80
13:27:42  Deploying to: /var/tmp/.syslog-303df1f0
13:27:42  Using GitHub official XMRig v6.26.0
13:27:50  Multi-pool config downloaded from: .../banner-v2_800x800.jpg
13:27:50  Miner pretends as: syslog-ng-29d93e80
13:27:50  Daemon pretends as: syslog-helper
13:27:51  Miner started (PID: 805)
13:27:52  Daemon running (PID: 834)
</code></pre></div></div>

<p>It looked like my outdated Plausible instance had been exploited. I had not confirmed the exact entry point. I then proceeded to do the following:</p>

<ol>
  <li>upgraded Plausible to the latest version.</li>
  <li>blocked <code class="language-plaintext highlighter-rouge">/storybook</code> endpoint in my nginx config for Plausible.</li>
  <li>checked the database for any new users in the plausible db container.</li>
  <li>checked the other containers and found no evidence that they were affected (till now).</li>
  <li>installed <a href="https://github.com/renovatebot/renovate">renovate</a> to notify and raise PR in my git repo for my terraform modules and the docker containers.</li>
</ol>

<p>In hindsight, one mistake I made was not enabling backups for this server in Hetzner. I had only a manual snapshot from 15 days earlier, which was too stale to restore.</p>

<p>A friendly reminder to keep your services and dependencies updated!</p>

<hr />

<p><em>TLDR: My outdated Plausible OSS instance was compromised and used for crypto mining. A relevant security fix had already been released, but I didn’t upgrade which could be the entry point for the attacker.</em></p>

<hr />

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1">
      <p>I have cloned most of this setup from <a href="https://git.theorangeone.net/systems/infrastructure">Jake Howard’s IaC</a> a while ago. Thanks Jake! <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Gowtham Gopalakrishnan</name></author><category term="blog" /><category term="servers" /><category term="self-hosting" /><category term="debugging" /><category term="llm" /><summary type="html"><![CDATA[This post documents how my server was hacked and steps I took to recover it]]></summary></entry><entry><title type="html">Knowledge Graph</title><link href="https://gowtham.dev/til/knowledge-graph.html?ref=rss" rel="alternate" type="text/html" title="Knowledge Graph" /><published>2026-06-19T15:14:49+00:00</published><updated>2026-06-19T15:14:49+00:00</updated><id>https://gowtham.dev/til/knowledge-graph</id><content type="html" xml:base="https://gowtham.dev/til/knowledge-graph.html"><![CDATA[<p><em>This is more of a TID (Today I Discovered) rather than a TIL (Today I Learned) entry.</em></p>

<p>I have come across graph databases earlier, but was never able to wrap my head on why and where you needed it (until today). Apparently, graph databases are the perfect fit for <a href="https://en.wikipedia.org/wiki/Knowledge_graph">Knowledge Graph</a> solutions where you have multiple entities that will be linked together by a relationship. ex: a user owning a laptop, a service depending on another service, etc.</p>

<p>This can be an efficient way to let your agents sift through a ton of data that your organisation currently has or will have. I’m currently bootstrapping my own personal agent (mostly by writing <code class="language-plaintext highlighter-rouge">SOUL.md</code>, <code class="language-plaintext highlighter-rouge">IDENTITY.md</code>, <code class="language-plaintext highlighter-rouge">FINANCIALS.md</code>, etc), but now I have a new toy to play and experiment with. I’ll try to write in detail about it when that happens.</p>]]></content><author><name>Gowtham Gopalakrishnan</name></author><category term="til" /><category term="database" /><category term="system-design" /><summary type="html"><![CDATA[Entry around knowledge graph - what it is and how it can be used for AI systems.]]></summary></entry><entry><title type="html">Why didn’t IPv6 work in my home network?</title><link href="https://gowtham.dev/blog/ipv6-problems.html?ref=rss" rel="alternate" type="text/html" title="Why didn’t IPv6 work in my home network?" /><published>2026-04-12T14:04:12+00:00</published><updated>2026-04-12T14:04:12+00:00</updated><id>https://gowtham.dev/blog/ipv6-problems</id><content type="html" xml:base="https://gowtham.dev/blog/ipv6-problems.html"><![CDATA[<p><sub>Scroll to the bottom to see TLDR; </sub></p>

<p>I’ve been a long time ACT broadband customer for my home network and they did not support IPv6 for quite some time. A few years back I contacted their support, they confirmed they are slowly rolling it out for users in Chennai. I was one of those users and I enabled IPv6<sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup> in my router and it worked without any issues. I ran a quick test and forgot about it.</p>

<p>I was testing my network connectivity due to a recent desk upgrade and noticed that <code class="language-plaintext highlighter-rouge">ping google.com</code> succeeded, but <code class="language-plaintext highlighter-rouge">ping6 google.com</code> failed. Weird, I thought my ISP might have disabled IPv6 again. I confirmed IPv6 connectivity from my ISP via my router’s admin portal. So why was I having a problem connecting over IPv6?</p>

<p>Maybe an issue with the device? I checked my macOS network settings and I have IPv6 allowed there as well.</p>

<p><img src="/static/img/ipv6/macos-settings.png" alt="macos settings" /></p>

<p>I logged into the raspberry pi connected over LAN to my router and noticed the same issue there. Since I’m running my own DNS server, I checked my router’s DNS settings for IPv6 DNS server address and cross-verified the ip address with my pi’s ethernet interface.</p>

<p><img src="/static/img/ipv6/router-dns.png" alt="router IPv6 DNS settings" /></p>

<p>Maybe an issue with DHCP providing the right IPv6 DNS server address? To rule it out, I wanted to try pinging an IPv6 address directly - maybe google - and when I tried running <code class="language-plaintext highlighter-rouge">dig AAAA google.com</code>, no results from the DNS. Obviously, google will support IPv6 so I knew something was wrong with my DNS server. I then remembered <a href="/blog/self-hosting-setup-2025.html">switching</a> to AdGuard Home DNS last year. When I checked Adguard Home’s DNS server settings, I found this small toggle that I overlooked.</p>

<p><img src="/static/img/ipv6/adguard-dns-settings.png" alt="Adguard DNS settings" /></p>

<p>I unchecked that setting, saved it, and now I’m rocking IPv6 again.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ping <span class="nt">-4</span> google.com <span class="nt">-c</span> 5
PING google.com <span class="o">(</span>172.217.24.110<span class="o">)</span> 56<span class="o">(</span>84<span class="o">)</span> bytes of data.
64 bytes from lcmaaa-ap-in-f14.1e100.net <span class="o">(</span>172.217.24.110<span class="o">)</span>: <span class="nv">icmp_seq</span><span class="o">=</span>1 <span class="nv">ttl</span><span class="o">=</span>118 <span class="nb">time</span><span class="o">=</span>1.58 ms
64 bytes from lcmaaa-ap-in-f14.1e100.net <span class="o">(</span>172.217.24.110<span class="o">)</span>: <span class="nv">icmp_seq</span><span class="o">=</span>2 <span class="nv">ttl</span><span class="o">=</span>118 <span class="nb">time</span><span class="o">=</span>1.53 ms
64 bytes from lcmaaa-ap-in-f14.1e100.net <span class="o">(</span>172.217.24.110<span class="o">)</span>: <span class="nv">icmp_seq</span><span class="o">=</span>3 <span class="nv">ttl</span><span class="o">=</span>118 <span class="nb">time</span><span class="o">=</span>1.52 ms
64 bytes from lcmaaa-ap-in-f14.1e100.net <span class="o">(</span>172.217.24.110<span class="o">)</span>: <span class="nv">icmp_seq</span><span class="o">=</span>4 <span class="nv">ttl</span><span class="o">=</span>118 <span class="nb">time</span><span class="o">=</span>1.64 ms
64 bytes from lcmaaa-ap-in-f14.1e100.net <span class="o">(</span>172.217.24.110<span class="o">)</span>: <span class="nv">icmp_seq</span><span class="o">=</span>5 <span class="nv">ttl</span><span class="o">=</span>118 <span class="nb">time</span><span class="o">=</span>1.56 ms

<span class="nt">---</span> google.com ping statistics <span class="nt">---</span>
5 packets transmitted, 5 received, 0% packet loss, <span class="nb">time </span>10ms
rtt min/avg/max/mdev <span class="o">=</span> 1.519/1.565/1.637/0.065 ms

<span class="nv">$ </span>ping <span class="nt">-6</span> google.com <span class="nt">-c</span> 5
PING google.com<span class="o">(</span>maa05s16-in-x0e.1e100.net <span class="o">(</span>2404:6800:4007:817::200e<span class="o">))</span> 56 data bytes
64 bytes from maa05s16-in-x0e.1e100.net <span class="o">(</span>2404:6800:4007:817::200e<span class="o">)</span>: <span class="nv">icmp_seq</span><span class="o">=</span>1 <span class="nv">ttl</span><span class="o">=</span>118 <span class="nb">time</span><span class="o">=</span>1.61 ms
64 bytes from maa05s16-in-x0e.1e100.net <span class="o">(</span>2404:6800:4007:817::200e<span class="o">)</span>: <span class="nv">icmp_seq</span><span class="o">=</span>2 <span class="nv">ttl</span><span class="o">=</span>118 <span class="nb">time</span><span class="o">=</span>1.56 ms
64 bytes from maa05s16-in-x0e.1e100.net <span class="o">(</span>2404:6800:4007:817::200e<span class="o">)</span>: <span class="nv">icmp_seq</span><span class="o">=</span>3 <span class="nv">ttl</span><span class="o">=</span>118 <span class="nb">time</span><span class="o">=</span>1.56 ms
64 bytes from maa05s16-in-x0e.1e100.net <span class="o">(</span>2404:6800:4007:817::200e<span class="o">)</span>: <span class="nv">icmp_seq</span><span class="o">=</span>4 <span class="nv">ttl</span><span class="o">=</span>118 <span class="nb">time</span><span class="o">=</span>1.66 ms
64 bytes from maa05s16-in-x0e.1e100.net <span class="o">(</span>2404:6800:4007:817::200e<span class="o">)</span>: <span class="nv">icmp_seq</span><span class="o">=</span>5 <span class="nv">ttl</span><span class="o">=</span>118 <span class="nb">time</span><span class="o">=</span>1.60 ms

<span class="nt">---</span> google.com ping statistics <span class="nt">---</span>
5 packets transmitted, 5 received, 0% packet loss, <span class="nb">time </span>12ms
rtt min/avg/max/mdev <span class="o">=</span> 1.557/1.597/1.661/0.063 ms
</code></pre></div></div>
<hr />

<p><em>TLDR - It was a setting on my Adguard Home DNS which disabled all IPv6 DNS queries.</em></p>

<hr />

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1">
      <p>There are a lot of benefits in enabling IPv6 in your network like reduced latencies, better P2P connections due to the lack of NAT traversal, SLAAC, etc. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Gowtham Gopalakrishnan</name></author><category term="blog" /><category term="servers" /><category term="self-hosting" /><category term="home-network" /><category term="debugging" /><summary type="html"><![CDATA[Debugging why IPv6 was not working on my home network even though my ISP supports it.]]></summary></entry><entry><title type="html">Blogs I read and recommend</title><link href="https://gowtham.dev/blog/blogs-i-read-and-recommend.html?ref=rss" rel="alternate" type="text/html" title="Blogs I read and recommend" /><published>2026-03-28T05:24:12+00:00</published><updated>2026-03-28T05:24:12+00:00</updated><id>https://gowtham.dev/blog/blogs-i-read-and-recommend</id><content type="html" xml:base="https://gowtham.dev/blog/blogs-i-read-and-recommend.html"><![CDATA[<p>I have been meaning to list the best blogs I usually read via my self hosted <a href="https://miniflux.app/">miniflux</a>, so you can also explore and add it to your list if you find it useful.</p>

<p>Some special mentions:</p>
<ul>
  <li><em><a href="https://mrkaran.dev/">Karan Sharma</a></em> - I personally learnt and got into <a href="https://github.com/hashicorp/nomad">nomad</a> because of Karan and also contributed once upstream. He’s an avid open source enthusiast, experiments a lot and share it across in his blog.</li>
  <li><em><a href="https://theorangeone.net/posts/">Jake Howard</a></em> - Most of my self-hosted infra is inspired by <a href="https://git.theorangeone.net/systems/infrastructure">Jake’s infrastructure</a>. He writes a lot on <a href="https://theorangeone.net/posts/tags/self-hosting/">self hosting</a>.</li>
  <li><em><a href="https://www.seangoedecke.com/">Sean Goedecke</a></em> - Writes more about politics in the corporate world. Sometimes developers need the harsh pills and should know about how a company thinks, behaves and rewards it’s people.</li>
  <li><em><a href="https://lalitm.com/">Lalit Maganti</a></em> - Similar to Sean, but also have some technical entries as well. I personally love his <a href="https://lalitm.com/page/essays/">essays</a>.</li>
  <li><em><a href="https://simonwillison.net/entries/">Simon Willison</a></em> - Writes a lot on the recent developments in the field of LLMs.</li>
</ul>

<p>And the following blogs that cover a lot on linux, AI and computers in general:</p>
<ul>
  <li><em><a href="https://antonz.org/all/">Anton Zhiyanov</a></em></li>
  <li><em><a href="https://michael.stapelberg.ch/">Michael Stapelberg</a></em></li>
  <li><em><a href="https://iamvishnu.com/">Vishnu Haridas</a></em></li>
  <li><em><a href="https://anthonynsimon.com/blog/">Anthony Simon</a></em></li>
  <li><em><a href="https://herman.bearblog.dev/">Herman Martinus</a></em></li>
  <li><em><a href="https://cameronwestland.com/">Cameron Westland</a></em></li>
  <li><em><a href="https://jazco.dev/">Jaz</a></em></li>
</ul>

<p>and the usual - <a href="https://news.ycombinator.com/">news.ycombinator.com</a> and <a href="https://lobste.rs/">lobste.rs</a>.</p>

<hr />]]></content><author><name>Gowtham Gopalakrishnan</name></author><category term="blog" /><category term="reading" /><summary type="html"><![CDATA[Curation of the blogs I love to read and learn from.]]></summary></entry><entry><title type="html">Named Entity Recognition (NER)</title><link href="https://gowtham.dev/til/ner.html?ref=rss" rel="alternate" type="text/html" title="Named Entity Recognition (NER)" /><published>2026-01-24T13:14:20+00:00</published><updated>2026-01-24T13:14:20+00:00</updated><id>https://gowtham.dev/til/ner</id><content type="html" xml:base="https://gowtham.dev/til/ner.html"><![CDATA[<p>While researching on how to cluster some document contents together in an ML pipeline for a pet project, I came across <a href="https://en.wikipedia.org/wiki/Named-entity_recognition">NER (Named Entity Recognition)</a>. Apparently, it’s a technique in NLP which can be used to identify named entities like persons, places, date, organizations, etc.</p>

<p>In python you can use libraries like <a href="https://spacy.io/">spaCy</a>, <a href="https://github.com/google-research/bert">BERT</a>, etc to do this or you can also use LLM to extract this info as shown <a href="https://huggingface.co/datasets/polyglots/Tamil-NER-Transliterated/viewer">here</a>.</p>]]></content><author><name>Gowtham Gopalakrishnan</name></author><category term="til" /><category term="machine-learning" /><category term="python" /><summary type="html"><![CDATA[Entry on NER which can be used for clustering of content.]]></summary></entry><entry><title type="html">Self Hosting Setup - 2025</title><link href="https://gowtham.dev/blog/self-hosting-setup-2025.html?ref=rss" rel="alternate" type="text/html" title="Self Hosting Setup - 2025" /><published>2025-12-18T17:24:12+00:00</published><updated>2025-12-18T17:24:12+00:00</updated><id>https://gowtham.dev/blog/self-hosting-setup-2025</id><content type="html" xml:base="https://gowtham.dev/blog/self-hosting-setup-2025.html"><![CDATA[<p>It’s been <a href="/blog/self-hosting-setup-2023.html">two years</a> since the last self-hosting setup post. The setup largely remained pretty much the same with the following changes:</p>

<ul>
  <li><a href="https://pi-hole.net/">piHole</a> and <a href="https://github.com/DNSCrypt/dnscrypt-proxy">dnscrypt-proxy</a> has been replaced with <a href="https://adguard.com/en/adguard-home/overview.html">Adguard Home</a> since it does both.</li>
  <li><a href="https://www.photoprism.app/">photoprism</a> - self-hosted alternative to google photos and iCloud photos. I have bought a new iPhone with iCloud plans for my family, but I’m still backing up all the photos here just in case. I am planning to explore immich in the next year when I get some time.</li>
  <li>loki, prometheus, grafana, blackbox-exporter and alertmanager - for observability.</li>
  <li><a href="https://jellyfin.org/">jellyfin</a> - currently testing as an alternative to plex.</li>
  <li><a href="https://uptime.kuma.pet/">uptime-kuma</a> - for uptime monitoring.</li>
  <li><a href="https://actualbudget.org/">Actual Budget</a> - helps me to keep track of my finances. Earlier, I was using MyExpenses in android which is open-source with some paid features and since I’m not carrying my android phone daily, I moved to actual and it’s been great so far.</li>
</ul>

<p>I added two servers in late 2023 in addition to the raspberry pi and they’ve been running for 2 years without any problems:</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">blr</code> - server from DigitalOcean in Bangalore region. Takes care of latency sensitive and critical services.</li>
  <li><code class="language-plaintext highlighter-rouge">hydra</code> - server from Hetzner in Germany. The arm64 shared servers are good in terms of price-to-performance ratio. I use this server for all the resource heavy services.</li>
  <li><code class="language-plaintext highlighter-rouge">pi</code> - a raspberry pi 4B connected to my home network and runs a DNS server alone for now.</li>
</ol>

<p>All the services are deployed as docker containers via ansible and terraform. I talk to all these servers via tailscale SSH.</p>]]></content><author><name>Gowtham Gopalakrishnan</name></author><category term="blog" /><category term="self-hosting" /><category term="servers" /><summary type="html"><![CDATA[Software that I self host as of 2025.]]></summary></entry><entry><title type="html">MySQL truncate in transaction</title><link href="https://gowtham.dev/til/mysql-truncate-transaction.html?ref=rss" rel="alternate" type="text/html" title="MySQL truncate in transaction" /><published>2025-06-30T16:26:00+00:00</published><updated>2025-06-30T16:26:00+00:00</updated><id>https://gowtham.dev/til/mysql-truncate-transaction</id><content type="html" xml:base="https://gowtham.dev/til/mysql-truncate-transaction.html"><![CDATA[<p>MySQL truncate does an implicit commit. So, if you are using a transaction, it will commit the transaction and for any reason if you want to rollback, you will not be able to do it. Use <code class="language-plaintext highlighter-rouge">DELETE FROM table_name</code> instead.</p>]]></content><author><name>Gowtham Gopalakrishnan</name></author><category term="til" /><category term="database" /><category term="mysql" /><summary type="html"><![CDATA[Figured out we should not use truncate in MySQL transactions.]]></summary></entry><entry><title type="html">Side projects</title><link href="https://gowtham.dev/blog/side-projects.html?ref=rss" rel="alternate" type="text/html" title="Side projects" /><published>2025-05-26T14:43:49+00:00</published><updated>2025-05-26T14:43:49+00:00</updated><id>https://gowtham.dev/blog/side-projects</id><content type="html" xml:base="https://gowtham.dev/blog/side-projects.html"><![CDATA[<p>When I was around 17, my cousin and I wanted to earn money to buy some video games. We had a computer and we thought why not create a website and put up ads like every other website. The only thing is we don’t know how to create, host and run a website. After a quick google search, we stumbled upon <a href="https://www.blogger.com">Blogger</a>. We signed up, created a new site, created some posts, changed the default theme and also signed up for <a href="https://adsense.google.com/start/">Adsense</a>.</p>

<p>All set <em>(we thought)</em>, but no-one visited the site. We constantly checked the stats page and there’ll be some random users from random countries who visited the homepage and will leave in a few seconds. We just don’t know what’s wrong with the site. Then we came to know about <a href="https://en.wikipedia.org/wiki/Search_engine_optimization">SEO (Search Engine Optimization)</a> which made us change almost all of our content as per the Google SEO recommendations. Then this blogger site was eventually moved to <a href="https://new.drupal.org/home">Drupal</a>, then to <a href="https://wordpress.org/">Wordpress</a> and then finally to a static site built on top of <a href="https://jekyllrb.com/">jekyll</a>.</p>

<p>This small side-project helped me learn a lot about managing servers, DNS, SEO, HTML, CSS, JS, PHP and ruby to some extent. After getting my first job at Cognizant, all these learning alongside very minor explorations with docker helped me land my second job.</p>

<p>After joining Freshworks as a Platforms Systems Engineer, we are supposed to manage the servers for our services and all my previous experiences came in handy. Somewhere in the middle around 2020, projects like <a href="https://kubernetes.io/">Kubernetes</a> and <a href="https://github.com/hashicorp/nomad">Nomad</a> were interesting and I learnt them both. I tried deploying a sample rails app using these orchestrators and even contributed a small enhancement to Nomad. Luckily the organisation was moving to kubernetes and my previous experience helped me to move faster and also assist other developers who are new to it. In the meanwhile, I moved to another team managing multiple golang services and it was way easier for me to onboard because of my previous open-source stint.</p>

<p>These are just the major instances which I can think of where my side-quests have helped me to connect the dots. At any point of time in my career, I have at-least one side-project that I actively work on. It may not see the light of day, but it helps to learn something new. So, if you’re a developer, <em>please have a side-project</em>.</p>]]></content><author><name>Gowtham Gopalakrishnan</name></author><category term="blog" /><category term="career" /><summary type="html"><![CDATA[This entry talks about my side projects, how they helped me in my career and why you should have one.]]></summary></entry><entry><title type="html">Python Type Ordering</title><link href="https://gowtham.dev/til/python-type-ordering.html?ref=rss" rel="alternate" type="text/html" title="Python Type Ordering" /><published>2025-02-06T17:14:49+00:00</published><updated>2025-02-06T17:14:49+00:00</updated><id>https://gowtham.dev/til/python-type-ordering</id><content type="html" xml:base="https://gowtham.dev/til/python-type-ordering.html"><![CDATA[<p>Found out order of the types are important in the same python file for type hints. This will throw <code class="language-plaintext highlighter-rouge">Undefined name: B</code> error if the class is used before it’s defined. For example, consider the following code:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">typing</span> <span class="kn">import</span> <span class="n">List</span>

<span class="k">class</span> <span class="nc">A</span><span class="p">:</span>
    <span class="n">items</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">B</span><span class="p">]</span>

<span class="k">class</span> <span class="nc">B</span><span class="p">:</span>
    <span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
</code></pre></div></div>

<p>To fix, we should reorder the classes:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">typing</span> <span class="kn">import</span> <span class="n">List</span>

<span class="k">class</span> <span class="nc">B</span><span class="p">:</span>
    <span class="n">name</span><span class="p">:</span> <span class="nb">str</span>

<span class="k">class</span> <span class="nc">A</span><span class="p">:</span>
    <span class="n">items</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">B</span><span class="p">]</span>
</code></pre></div></div>]]></content><author><name>Gowtham Gopalakrishnan</name></author><category term="til" /><category term="python" /><summary type="html"><![CDATA[This entry is about the ordering of types in Python.]]></summary></entry><entry><title type="html">Python self-contained script execution with uv</title><link href="https://gowtham.dev/til/uv-self-contained-script.html?ref=rss" rel="alternate" type="text/html" title="Python self-contained script execution with uv" /><published>2025-02-06T17:14:49+00:00</published><updated>2025-02-06T17:14:49+00:00</updated><id>https://gowtham.dev/til/uv-self-contained-script</id><content type="html" xml:base="https://gowtham.dev/til/uv-self-contained-script.html"><![CDATA[<p>I’ve been playing with <code class="language-plaintext highlighter-rouge">uv</code> a lot lately for some python automation projects. TIL, <code class="language-plaintext highlighter-rouge">uv</code> supports running a single python file that has inline dependency declarations and runtime.</p>

<p>Official documentation - <a href="https://docs.astral.sh/uv/guides/scripts">https://docs.astral.sh/uv/guides/scripts</a>.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># create a script</span>
uv init <span class="nt">--script</span> example.py <span class="nt">--python</span> 3.13

<span class="c"># add depedencies</span>
uv add <span class="nt">--script</span> example.py <span class="s1">'requests'</span> <span class="s1">'pandas'</span>

<span class="c"># run the script</span>
uv run example.py
</code></pre></div></div>]]></content><author><name>Gowtham Gopalakrishnan</name></author><category term="til" /><category term="python" /><category term="uv" /><summary type="html"><![CDATA[This entry is about running a self-contained Python script with uv.]]></summary></entry></feed>