<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Yash Agarwal</title><description>Yash Agarwal writes about software engineering, infrastructure, and things he is building.</description><link>https://yashagarwal.in/</link><language>en-us</language><item><title>Self-hosting Umami with Cloudflare Workers as Proxy</title><link>https://yashagarwal.in/notes/self-hosting-umami-with-cloudflare-workers-as-proxy/</link><guid isPermaLink="true">https://yashagarwal.in/notes/self-hosting-umami-with-cloudflare-workers-as-proxy/</guid><description>How to self-host Umami analytics using Cloudflare Workers as a proxy server.</description><pubDate>Sat, 27 Dec 2025 04:40:32 GMT</pubDate><content:encoded>&lt;h1 id=&quot;why&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#why&quot;&gt;Why?&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I have been using &lt;a href=&quot;https://vercel.com/docs/analytics&quot;&gt;Vercel Analytics&lt;/a&gt; and &lt;a href=&quot;https://www.cloudflare.com/en-in/web-analytics/&quot;&gt;Cloudflare Web Analytics&lt;/a&gt; for tracking the traffic on this blog. While both services are great, I wanted to explore self-hosting an analytics solution to have more control over my data. After some research, I decided to use &lt;a href=&quot;https://umami.is/&quot;&gt;Umami&lt;/a&gt;, a simple, open-source, privacy-focused web analytics tool. I have used Umami before, when &lt;a href=&quot;https://planetscale.com/docs/plans/hobby-plan-deprecation-faq&quot;&gt;PlanetScale&lt;/a&gt; used to have a free tier for their serverless MySQL database. Meanwhile, Umami also &lt;a href=&quot;https://docs.umami.is/docs/guides/migrate-v1-v2&quot;&gt;migrated&lt;/a&gt; from v1 to v2 and with that came the headache of database migration. Since PlanetScale had discontinued their free tier, I ditched Umami and moved to Vercel and Cloudflare for managing the analytics for this blog.&lt;/p&gt;
&lt;p&gt;Recently, I bought a Raspberry Pi 5 to set up a home server for various projects. I thought it would be a great opportunity to self-host Umami on my Raspberry Pi. Only one issue – I don&apos;t have a UPS and I can&apos;t ensure 24x7 uptime for my Raspberry Pi server. This meant that if my home internet goes down or there&apos;s a power outage, my Umami instance would be inaccessible. I needed a solution that would allow me to self-host my Umami instance while being accessible on the public internet. I also needed a way to ensure that I don&apos;t lose any analytics data during Pi downtime.&lt;/p&gt;
&lt;p&gt;This post outlines various steps I took to build a system matching my requirements using Cloudflare Workers as a proxy server and Cloudflare Durable Objects as temporary storage, while staying within the free tier limits of Cloudflare.&lt;/p&gt;
&lt;h1 id=&quot;setting-up-raspberry-pi&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#setting-up-raspberry-pi&quot;&gt;Setting up Raspberry Pi&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This was the easiest part of the process. I followed the official &lt;a href=&quot;https://umami.is/docs/installation&quot;&gt;Umami installation guide&lt;/a&gt; to set up Umami on my Raspberry Pi. I used Docker to run the Umami instance and connected it to a local PostgreSQL database also running in a Docker container.&lt;/p&gt;
&lt;p&gt;This process exposed my Umami instance on my localhost at port 3000. Now I needed to find a way to access this instance from the public internet. I have past experience using &lt;a href=&quot;https://yashagarwal.in/homelab-using-cloudflared&quot;&gt;Cloudflare Tunnels&lt;/a&gt; to expose local services to the internet so this wasn&apos;t too difficult to set up either.&lt;/p&gt;
&lt;p&gt;Here&apos;s the Docker Compose configuration I used:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# docker-compose.yml&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;version&lt;/span&gt;: &apos;3&apos;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;services&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  umami&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    image&lt;/span&gt;: ghcr.io/umami-software/umami:postgresql-latest
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    ports&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;3000:3000&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    environment&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      DATABASE_URL&lt;/span&gt;: postgresql://umami:umami@db:5432/umami
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      DATABASE_TYPE&lt;/span&gt;: postgresql
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      APP_SECRET&lt;/span&gt;: ${APP_SECRET} # Generate with: openssl rand -base64 32
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    depends_on&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      db&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;        condition&lt;/span&gt;: service_healthy
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    restart&lt;/span&gt;: always
 
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  db&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    image&lt;/span&gt;: postgres:15-alpine
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    environment&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      POSTGRES_DB&lt;/span&gt;: umami
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      POSTGRES_USER&lt;/span&gt;: umami
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      POSTGRES_PASSWORD&lt;/span&gt;: umami
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    volumes&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;umami-db-data:/var/lib/postgresql/data
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    restart&lt;/span&gt;: always
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    healthcheck&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      test&lt;/span&gt;: [&quot;CMD-SHELL&quot;, &quot;pg_isready -U umami -d umami&quot;]
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      interval&lt;/span&gt;: 5s
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      timeout&lt;/span&gt;: 5s
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      retries&lt;/span&gt;: 5
 
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  cloudflared&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    image&lt;/span&gt;: cloudflare/cloudflared:latest
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    command&lt;/span&gt;: tunnel --no-autoupdate run
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    environment&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      TUNNEL_TOKEN&lt;/span&gt;: ${TUNNEL_TOKEN}
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    restart&lt;/span&gt;: always
 
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;volumes&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  umami-db-data&lt;/span&gt;:&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;setting-up-cloudflare-tunnel&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#setting-up-cloudflare-tunnel&quot;&gt;Setting up Cloudflare Tunnel&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now comes the interesting part. I wanted to expose my Raspberry Pi directly to the public internet without a static IP or opening any ports on my router. &lt;a href=&quot;https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/&quot;&gt;Cloudflare Tunnels&lt;/a&gt; provide a secure way to expose local services to the internet without needing a public IP address or port forwarding. The tunnel creates an outbound connection from my Raspberry Pi to Cloudflare&apos;s network, allowing me to access my Umami instance securely.&lt;/p&gt;
&lt;p&gt;Setting up the tunnel was straightforward:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Create a tunnel&lt;/strong&gt; from the Cloudflare dashboard under Networks → Tunnels or using the Cloudflare Tunnel CLI:&lt;/li&gt;
&lt;/ol&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;cloudflared&lt;/span&gt; tunnel create umami-tunnel&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;Generate a tunnel token&lt;/strong&gt; - The CLI autogenerates this.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configure the tunnel token&lt;/strong&gt; in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;.env&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file:&lt;/li&gt;
&lt;/ol&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# .env&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;TUNNEL_TOKEN&lt;/span&gt;=&amp;#x3C;your-tunnel-token-here&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;APP_SECRET&lt;/span&gt;=&amp;#x3C;generate-with-openssl-rand-base64-32&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;&lt;strong&gt;Configure ingress in the Cloudflare dashboard&lt;/strong&gt; - this is where the magic happens. Instead of creating a public hostname like &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;umami.yourdomain.com&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, I configured the ingress to route traffic from the tunnel to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;http://umami:3000&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; (the Umami service in Docker Compose).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Start everything with Docker Compose:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;docker-compose&lt;/span&gt; up -d
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Verify all services are running&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;docker-compose&lt;/span&gt; ps
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Check cloudflared logs to confirm tunnel connection&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;docker-compose&lt;/span&gt; logs cloudflared&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;You should see something like:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;cloudflared  | Connection &amp;#x3C;UUID&gt; registered connIndex=0 ip=&amp;#x3C;IP&gt; location=&amp;#x3C;LOCATION&gt;&lt;/span&gt;
&lt;span&gt;cloudflared  | Registered tunnel connection&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;At this point, my Umami instance was accessible via the private tunnel URL, but &lt;strong&gt;only&lt;/strong&gt; from within Cloudflare&apos;s infrastructure. Perfect for what I needed – a secure way to access my Pi from outside my home without exposing it to the wider internet.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-blog-to-use-umami&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#setting-up-blog-to-use-umami&quot;&gt;Setting up blog to use Umami&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;My first approach was simple:&lt;/strong&gt; expose the Cloudflare Tunnel to the public internet by creating a DNS record that pointed directly to the tunnel. This allowed my blog to connect to the self-hosted Umami instance.&lt;/p&gt;
&lt;p&gt;The next step was to configure my blog to use this Umami instance for analytics. I logged into the Umami dashboard and created a new website entry for my blog. Once configured, I copied the website ID and updated my blog&apos;s configuration to use the new Umami instance.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;head&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;script
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;    is:inline&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;    defer&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;    src&lt;/span&gt;=&quot;https://umami.yashagarwal.in/script.js&quot;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;    data-website-id&lt;/span&gt;={UmamiWebsiteId}
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &gt;&amp;#x3C;/&lt;/span&gt;script&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;head&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;With this setup, my blog was now sending analytics data to my self-hosted Umami instance running on my Raspberry Pi, accessible via the Cloudflare Tunnel.&lt;/p&gt;
&lt;p&gt;However, what happens when my Raspberry Pi goes offline, either due to power outage or internet issues?&lt;/p&gt;
&lt;figure data-astro-cid-s57xbq3y=&quot;&quot;&gt; &lt;div data-excalidraw-svg=&quot;&quot; data-astro-cid-s57xbq3y=&quot;&quot;&gt; &lt;img src=&quot;https://yashagarwal.in/_astro/pi-offline-without-worker.BPQaTMKK.svg&quot; alt=&quot;Diagram showing analytics requests failing when Raspberry Pi is offline, resulting in lost data&quot; data-astro-cid-s57xbq3y=&quot;&quot;&gt; &lt;/div&gt; &lt;figcaption data-astro-cid-s57xbq3y=&quot;&quot;&gt;Without a proxy layer: requests fail when Pi is offline, resulting in lost analytics data&lt;/figcaption&gt; &lt;/figure&gt;  
&lt;p&gt;Since, I couldn&apos;t guarantee 24x7 uptime for my Raspberry Pi, I needed a way to ensure that analytics data was not lost during downtime. This is where Cloudflare Workers came into play.&lt;/p&gt;
&lt;h1 id=&quot;using-cloudflare-workers-as-proxy&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#using-cloudflare-workers-as-proxy&quot;&gt;Using Cloudflare Workers as Proxy&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;As clear from the above diagram, when the Raspberry Pi is offline, any requests to the Umami instance would fail, resulting in lost analytics data. To solve this problem, I decided to use Cloudflare Workers as a proxy layer between my blog and the Umami instance. &lt;a href=&quot;https://developers.cloudflare.com/workers/&quot;&gt;Cloudflare Workers&lt;/a&gt; are serverless functions that run on Cloudflare&apos;s edge network, allowing me to intercept and modify requests before they reach the origin server. Since I am already using Cloudflare Tunnels to expose my Umami instance, integrating Cloudflare Workers into the setup was the most obvious choice.&lt;/p&gt;
&lt;p&gt;To provide a storage mechanism for buffering analytics data during Pi downtime, I decided to use &lt;a href=&quot;https://developers.cloudflare.com/durable-objects/&quot;&gt;Cloudflare Durable Objects&lt;/a&gt;. It is a special type of Cloudflare Workers. Durable Objects provide a way to store stateful data in a distributed manner across Cloudflare&apos;s edge network. This meant that when the Raspberry Pi was offline, the Workers could temporarily store the analytics data in a persistent storage and forward them to the Umami instance once it came back online. Durable Objects also provide the &lt;a href=&quot;https://developers.cloudflare.com/durable-objects/api/alarms/&quot;&gt;alarm feature&lt;/a&gt;, which is essentially a timer that can be set to trigger a function after a specified interval. This feature is crucial for retrying the forwarding of buffered analytics data once the Raspberry Pi comes back online.&lt;/p&gt;
&lt;p&gt;Below sequence diagram illustrates the request flow when using Cloudflare Workers as a proxy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When a user visits my blog, the browser sends a request to the Cloudflare Workers proxy.&lt;/li&gt;
&lt;li&gt;The Workers intercept the request and check if the Raspberry Pi is online by attempting to forward the request to the Umami instance via the Cloudflare Tunnel.&lt;/li&gt;
&lt;li&gt;If the Raspberry Pi is online, the Workers forward the request to the Umami instance and return the response to the browser.&lt;/li&gt;
&lt;li&gt;If the Raspberry Pi is offline, the Workers store the analytics data in a Durable Object and set an alarm to retry forwarding the data after a specified interval.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure data-astro-cid-s57xbq3y=&quot;&quot;&gt; &lt;div data-excalidraw-svg=&quot;&quot; data-astro-cid-s57xbq3y=&quot;&quot;&gt; &lt;img src=&quot;https://yashagarwal.in/_astro/request-flow.DudWsFLQ.svg&quot; alt=&quot;Sequence diagram showing request flow from browser through Cloudflare Workers proxy to Raspberry Pi, with two scenarios: direct forwarding when Pi is online, and event buffering in Durable Objects with retry logic when Pi is offline&quot; data-astro-cid-s57xbq3y=&quot;&quot;&gt; &lt;/div&gt; &lt;figcaption data-astro-cid-s57xbq3y=&quot;&quot;&gt;Request flow with Workers proxy: direct forwarding when Pi is online, buffering with retry when offline&lt;/figcaption&gt; &lt;/figure&gt;  
&lt;h1 id=&quot;implementation-details&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#implementation-details&quot;&gt;Implementation Details&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&quot;cloudflare-workers-proxy&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#cloudflare-workers-proxy&quot;&gt;Cloudflare Workers Proxy&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The primary task of the Cloudflare Workers proxy is to intercept requests from the blog domain, and forward them to the Umami instance running on the Raspberry Pi via the Cloudflare Tunnel. The real magic happens when the Pi is offline.&lt;/p&gt;
&lt;p&gt;If the event forwarding to the Umami instance fails, it indicates that the Pi is offline. In this case, the Workers store the analytics data in its storage and set an alarm to retry forwarding the data after a specified interval. The client would receive a 202 Accepted response, indicating that the request has been accepted for processing, but the processing is not yet complete.&lt;/p&gt;
&lt;p&gt;Here is a high-level pseudocode of the Workers proxy logic:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;typescript&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;typescript&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;function&lt;/span&gt; handleEventProxy(request: Request): Response {
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    // 1. Validate request&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    if&lt;/span&gt; (request.size &gt; MAX_SIZE) {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;        return&lt;/span&gt; new Response(&apos;Payload Too Large&apos;, { status: 413 });
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    }&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    if&lt;/span&gt; (request.contentType !== &apos;application/json&apos;) {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;        return&lt;/span&gt; new Response(&apos;Unsupported Media Type&apos;, { status: 415 });
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    }&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    // 2. Parse and validate payload&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    const&lt;/span&gt; body = await request.json();
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    const&lt;/span&gt; payload = body.payload || body;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    if&lt;/span&gt; (payload.website !== UMAMI_WEBSITE_ID) {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;        return&lt;/span&gt; new Response(&apos;Invalid Website ID&apos;, { status: 400 });
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    }&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    // 3. Extract client metadata&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    const&lt;/span&gt; clientIP = request.headers.get(&apos;CF-Connecting-IP&apos;);
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    const&lt;/span&gt; userAgent = request.headers.get(&apos;User-Agent&apos;);
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    const&lt;/span&gt; geoHeaders = extractGeolocationHeaders(request);
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    // 4. Create event wrapper&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    const&lt;/span&gt; event = {
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        event_id: &lt;/span&gt;generateUUID(),
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        received_at: Date.&lt;/span&gt;now(),
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        payload: payload,&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        client_ip: clientIP,&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        user_agent: userAgent,&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        cf_headers: geoHeaders&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    };&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    // 5. Try direct delivery&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    try&lt;/span&gt; {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;        const&lt;/span&gt; response = await forwardToUmami(event);
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;        if&lt;/span&gt; (response.ok) {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;            return&lt;/span&gt; new Response(JSON.stringify({ success: true }), { status: 200 });
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        } &lt;/span&gt;else {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;            throw&lt;/span&gt; new Error(`Umami returned ${response.status}`);
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    } &lt;/span&gt;catch (error) {
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;        // 6. Pi is down - buffer for later&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;        await&lt;/span&gt; durableObject.buffer(event);
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;        return&lt;/span&gt; new Response(JSON.stringify({ success: true, buffered: true }), { status: 202 });
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;cloudflare-durable-object-for-buffering&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#cloudflare-durable-object-for-buffering&quot;&gt;Cloudflare Durable Object for Buffering&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Durable Object is responsible for storing the analytics data when the Raspberry Pi is offline. It maintains a queue of events and provides methods to buffer new events and retry forwarding them to the Umami instance.&lt;/p&gt;
&lt;p&gt;When an event is buffered, the Durable Object sets an alarm to trigger a retry after a specified interval. When the alarm goes off, the Durable Object attempts to forward all buffered events to the Umami instance. If the forwarding is successful, the events are removed from the queue. If it fails again, the events remain in the queue for future retries and are retried after exponential backoff. If an event has exceeded maximum retry attempts, we stop doing exponential backoffs and retry every 30 minutes until the event has been in queue for more than 24 hours.&lt;/p&gt;
&lt;p&gt;Here is a high-level pseudocode of the event buffering logic:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;typescript&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;typescript&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;// EventBuffer Durable Object&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;async&lt;/span&gt; function bufferEvent(proxyEvent: ProxyEvent): Promise&amp;#x3C;Response&gt; {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    const&lt;/span&gt; bufferedEvent = {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;        ...&lt;/span&gt;proxyEvent,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        retry_count: &lt;/span&gt;0,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        next_retry_at: Date.&lt;/span&gt;now() + 30_000, // 30s
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        buffered_at: Date.&lt;/span&gt;now()
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    };&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    await&lt;/span&gt; storage.put(proxyEvent.event_id, bufferedEvent);
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    ctx.&lt;/span&gt;waitUntil(flushBuffer());
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    await&lt;/span&gt; ensureAlarm();
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    return&lt;/span&gt; new Response(JSON.stringify({ buffered: true }), { status: 202 });
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;
 
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;async&lt;/span&gt; function flushBuffer(): Promise&amp;#x3C;void&gt; {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    const&lt;/span&gt; events = await storage.getAllEvents();
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    for&lt;/span&gt; (const [id, event] of events) {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;        if&lt;/span&gt; (event.next_retry_at &amp;#x3C;= Date.now()) {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;            await&lt;/span&gt; deliverEvent(id, event);
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    }&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    await&lt;/span&gt; ensureAlarm();
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;
 
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;async&lt;/span&gt; function deliverEvent(id: string, event: BufferedEvent): Promise&amp;#x3C;void&gt; {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    try&lt;/span&gt; {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;        const&lt;/span&gt; response = await forwardToUmami(event);
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;        if&lt;/span&gt; (response.ok) {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;            await&lt;/span&gt; storage.delete(id);
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;            return&lt;/span&gt;;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    } &lt;/span&gt;catch (error) {
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;        // Retry logic below&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    }&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    const&lt;/span&gt; newRetryCount = event.retry_count + 1;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    const&lt;/span&gt; age = Date.now() - event.buffered_at;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    if&lt;/span&gt; (newRetryCount &gt;= MAX_RETRIES &amp;#x26;&amp;#x26; age &gt; maxAge) {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;        await&lt;/span&gt; storage.delete(id);
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;        return&lt;/span&gt;;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    }&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    const&lt;/span&gt; interval = INTERVALS[newRetryCount] || MAX_INTERVAL;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    event.retry_count &lt;/span&gt;= newRetryCount;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    event.next_retry_at &lt;/span&gt;= Date.now() + interval;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    await&lt;/span&gt; storage.put(id, event);
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;
 
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;async&lt;/span&gt; function ensureAlarm(): Promise&amp;#x3C;void&gt; {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    const&lt;/span&gt; events = await storage.getAllEvents();
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    let&lt;/span&gt; nextRetry = Infinity;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    for&lt;/span&gt; (const [_, event] of events) {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;        if&lt;/span&gt; (event.next_retry_at &amp;#x3C; nextRetry) {
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;            nextRetry &lt;/span&gt;= event.next_retry_at;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    }&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    if&lt;/span&gt; (nextRetry !== Infinity) {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;        await&lt;/span&gt; storage.setAlarm(nextRetry);
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    } &lt;/span&gt;else {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;        await&lt;/span&gt; storage.deleteAlarm();
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;
 
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;async&lt;/span&gt; function alarm(): Promise&amp;#x3C;void&gt; {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    await&lt;/span&gt; flushBuffer();
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The retry strategy follows this state flow:&lt;/p&gt;
&lt;figure data-astro-cid-s57xbq3y=&quot;&quot;&gt; &lt;div data-excalidraw-svg=&quot;&quot; data-astro-cid-s57xbq3y=&quot;&quot;&gt; &lt;img src=&quot;https://yashagarwal.in/_astro/durable-objects-retry-flow.DP8go3mZ.svg&quot; alt=&quot;State diagram showing Durable Objects retry flow with exponential backoff: events are retried after 30 seconds, 5 minutes, and 15 minutes, with successful deliveries completing the flow and failed events being dropped after 24 hours&quot; data-astro-cid-s57xbq3y=&quot;&quot;&gt; &lt;/div&gt; &lt;figcaption data-astro-cid-s57xbq3y=&quot;&quot;&gt;Event retry flow in Durable Objects: exponential backoff with automatic cleanup after 24 hours&lt;/figcaption&gt; &lt;/figure&gt;  
&lt;h1 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This setup evolved from my need to self-host Umami on a Raspberry Pi with high availability. I didn&apos;t want to spend money on a VPS or third-party offerings, so I leveraged Cloudflare&apos;s free tier to build a robust (for now!) system. My blog doesn&apos;t receive too much traffic, so I hope to remain within the free tier limits of Cloudflare Durable Objects for the foreseeable future. Workers with Durable Objects provide a solid fallback mechanism to ensure no analytics data is lost during Pi downtime.&lt;/p&gt;
&lt;p&gt;I hope you enjoyed reading this post! If you have any questions or suggestions, feel free to reach out to me on &lt;a href=&quot;https://x.com/its_yash_btw&quot;&gt;X&lt;/a&gt; or via comments below. Do like and share if you found this post helpful!&lt;/p&gt;</content:encoded></item><item><title>My Bug of the Year (and How I Fixed It)</title><link>https://yashagarwal.in/notes/my-bug-of-the-year-and-how-i-fixed-it/</link><guid isPermaLink="true">https://yashagarwal.in/notes/my-bug-of-the-year-and-how-i-fixed-it/</guid><description>How a missing monkey.patch_all() turned my async Flask service into a synchronous bottleneck, creating zombie requests and wasting resources.</description><pubDate>Sun, 21 Dec 2025 11:05:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently worked on a Flask based microservice at work. While everything worked normally for the first few weeks, a few heavy traffic days unleashed a critical bug I had introduced inadvertently during development. This post is a detailed analysis of what went wrong and how I debugged and fixed the issue.&lt;/p&gt;
&lt;h1 id=&quot;the-background&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-background&quot;&gt;The Background&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I have been working with Python-based distributed systems with &lt;span x-data=&quot;&quot; x-tooltip.raw=&quot;Gevent is a coroutine-based Python networking library that uses greenlets for lightweight concurrency&quot;&gt; Gevent &lt;/span&gt; for concurrency for the last several years. However, I never got a chance to actually write a service that uses Gevent. Most of the services I have worked with were implemented by other teams and were in production for years before I started working on them. So, I never really got to experience writing a Gevent-based Python microservice from scratch. Recently, I got an opportunity to do just that. I was tasked with writing a new microservice that was to act as an email notification service for our platform. This service was replacing another service that belonged to a different product about to reach EOL.&lt;/p&gt;
&lt;h1 id=&quot;service-implementation&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#service-implementation&quot;&gt;Service Implementation&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;While I initially proposed using FastAPI for the new service, the team decided to go with Flask since most of our existing services were already using Flask. So, I started working on a new Flask-based microservice that exposed REST endpoints for the internal clients. Clients would call these endpoints with the request payload. The new notification service would process the payload and send email notifications by calling another downstream service over the network within the same K8s cluster.&lt;/p&gt;
&lt;p&gt;For the discussion in this post, the service had following tech stack -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Flask as the Web framework for implementing the business logic&lt;/li&gt;
&lt;li&gt;Gevent-based &lt;span x-data=&quot;&quot; x-tooltip.raw=&quot;Web Server Gateway Interface - the standard interface between Python web servers and web applications&quot;&gt; WSGI &lt;/span&gt; server as the Application server to handle HTTP requests&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I used Jaeger for distributed tracing so that we could trace requests across multiple services. We tested it for a couple of days in our staging environment, and everything seemed to be working fine. The service was able to handle a decent amount of load, and the traces were showing up correctly in Jaeger.&lt;/p&gt;
&lt;h1 id=&quot;deploying-to-production&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#deploying-to-production&quot;&gt;Deploying to Production&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;After about two weeks of testing in staging, I came up with a phase-wise rollout plan for deploying the new service to different production clusters. I started by routing a small percentage of the traffic to the new service while keeping the rest of the traffic going to the old service. I monitored the service closely for any issues. I gradually increased the traffic to the new service in phases until all the traffic was routed to the new service.&lt;/p&gt;
&lt;p&gt;Things were looking good until this point. In fact, the service didn&apos;t show any issues for the first few weeks. However, after about a month of running in the production environment, I started noticing some anomalies in the downstream email sending service. The email service started showing an abnormally high number of incoming requests from the new notification service. Initially, I thought that the clients were simply sending more requests than before. The email service started throttling requests from the notification service due to the high load. The Grafana charts were all showing a high number of HTTP requests being processed by the notification service and an equally high number of incoming requests on the email service side. However, the logs from the clients didn&apos;t show any increase in the number of requests being sent. This was puzzling.&lt;/p&gt;
&lt;h1 id=&quot;symptoms-start-appearing&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#symptoms-start-appearing&quot;&gt;Symptoms start appearing&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The sudden increase in the load on the email service raised quite a few eyebrows. I started investigating the issue from the notification service side to ensure that we were not dropping any notifications meant for the clients due to email service throttling. The service showed high throughput meaning the service was processing a high number of requests – an indicator of good performance in general. However the client side didn&apos;t show a significant increase in requests to the notification service. Though the number of requests from clients had increased, it was not corresponding to the number of requests being processed on the server.&lt;/p&gt;
&lt;p&gt;Another interesting observation was that the number of &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;context deadline exceeded&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; errors increased on the client. The clients were written in Golang and this error generally means that the requests were timing out. In fact, the client&apos;s http client was configured to timeout after 10 seconds. Once the timeout occurs, the client retries the requests. This was an important finding.&lt;/p&gt;
&lt;p&gt;Another thing I observed was the lack of tracing spans on the server side. I was able to find traces showing requests going out from the clients, but the spans from the Flask app layer were missing. This indicated that the Flask app was not processing requests. But then, how were the Grafana charts showing increased throughput?&lt;/p&gt;
&lt;p&gt;From the above findings, I was able to deduce a few things -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The client throughput had definitely increased but it was not consistently high. The throughput would increase only during business hours.&lt;/li&gt;
&lt;li&gt;The client was getting timeouts from the server and hence it was retrying with exponential backoff. The client timeout was 10 seconds per attempt, with retries continuing for up to 10 minutes total (15-17 retry attempts).&lt;/li&gt;
&lt;li&gt;The server was showing high throughput but it was not enough to process all requests from the client within the 10s timeout window.&lt;/li&gt;
&lt;li&gt;The downstream email service latency was around 500ms which wasn&apos;t concerning.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, in summary, the server was processing an unusually high number of requests but was still not able to process all the client requests. The client on the other hand showed a usual rate of requests in the logs (we didn&apos;t have any metrics on client side to show the outgoing request rate at that time) and high number of timeout errors.&lt;/p&gt;
&lt;h1 id=&quot;finally-a-breakthrough&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#finally-a-breakthrough&quot;&gt;Finally a breakthrough!&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Since I was not seeing any Jaeger spans from the Flask framework side, I suspected that the requests were not reaching the Flask server at all and were timing out (but not dropped!) at the WSGI server layer itself. When the client reaches its timeout (10s), Go cancels the context and closes the socket by calling the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;close()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; syscall. While I didn&apos;t debug the TCP layer, I suspect the client sent &lt;span x-data=&quot;&quot; x-tooltip.raw=&quot;TCP Reset packet - signals an abrupt connection termination&quot;&gt; RST packets &lt;/span&gt; causing an abrupt close. When a server receives a RST packet, any reads on the socket will result in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;connection reset by peer&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and writes will result in &lt;span x-data=&quot;&quot; x-tooltip.raw=&quot;Error that occurs when trying to write to a closed socket&quot;&gt; Broken pipe &lt;/span&gt; error. Gevent WSGI server catches these errors, logs them and then discards the response.&lt;/p&gt;
&lt;p&gt;Here are two possible scenarios that were in picture during this issue:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scenario 1: WSGI server read the entire request but Flask hasn&apos;t started processing&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP request is &lt;strong&gt;already buffered&lt;/strong&gt; in server memory&lt;/li&gt;
&lt;li&gt;Client RST doesn&apos;t affect buffered data&lt;/li&gt;
&lt;li&gt;When the greenlet runs, it processes the request normally&lt;/li&gt;
&lt;li&gt;Flask executes appropriate handler&lt;/li&gt;
&lt;li&gt;When trying to send response: &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;BrokenPipe&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; occurs&lt;/li&gt;
&lt;li&gt;Gevent catches exception, logs warning, continues&lt;/li&gt;
&lt;li&gt;Work is done, but client never knows = &lt;span&gt; ZOMBIE REQUEST &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Scenario 2: WSGI server read the request and Flask started processing&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Client RST arrives while handler is executing&lt;/li&gt;
&lt;li&gt;Python doesn&apos;t check socket state during processing&lt;/li&gt;
&lt;li&gt;Handler completes normally&lt;/li&gt;
&lt;li&gt;When trying to send response: &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;BrokenPipe&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; occurs&lt;/li&gt;
&lt;li&gt;Gevent catches exception, logs warning, continues&lt;/li&gt;
&lt;li&gt;Again a &lt;span&gt; Zombie request &lt;/span&gt;: work done, client never notified&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since the requests already accepted by the server were not dropped even when the client sent an RST packet, every retry added more requests to the server queue. These were all duplicate requests! Flask was able to process all these queued requests eventually; along with bombarding the email service with additional duplicate requests as a side effect. That explained increased throughput on Flask and email service.&lt;/p&gt;
&lt;p&gt;Since I was suspecting a high number of queued requests on the server side, I also decided to check the memory metrics for the Flask pods. And voila, I observed significantly increased memory usage on the pods. The CPU usage was moderate at about 50% usage consistently. But memory usage was above the 80% mark. In this process, I also found a minor bug in HPA configuration which prevented autoscaling on high memory usage. If the pods had autoscaled, the issue would not have come to light so quickly.&lt;/p&gt;
&lt;p&gt;So, the high memory usage answered what was happening. My hypothesis was clear now - clients were sending a high number of requests, the Gevent WSGI server was accepting all these requests and spawning &lt;span x-data=&quot;&quot; x-tooltip.raw=&quot;Ultra-lightweight cooperative threads that share the same OS thread and explicitly yield control to each other&quot;&gt; Greenlets &lt;/span&gt; to keep the requests in the memory. Flask was processing a high number of requests but it was still not enough to process all the Greenlets. Since some of the requests were timing out at the server layer, the client kept retrying the requests, adding to the load on the server.&lt;/p&gt;
&lt;p&gt;But, why was the Flask app not able to process all the requests?&lt;/p&gt;
&lt;h1 id=&quot;a-tale-of-pythons-single-threaded-nature-gevent-and-monkey-patching&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#a-tale-of-pythons-single-threaded-nature-gevent-and-monkey-patching&quot;&gt;A tale of Python&apos;s single threaded nature, Gevent and monkey patching&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Python is fundamentally single threaded due to &lt;span x-data=&quot;&quot; x-tooltip.raw=&quot;Global Interpreter Lock - Python&amp;#x27;s mechanism that prevents multiple threads from executing Python bytecode simultaneously&quot;&gt; GIL &lt;/span&gt;. Flask is also bound by this Python limitation. When a &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;socket.recv()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; or &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;requests.get()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is executed, the entire process just blocks and does nothing until this I/O completes. This is particularly bad for web applications because the process can&apos;t handle more than one request at a time.&lt;/p&gt;
&lt;p&gt;That&apos;s where Gevent shines. The solution is to use Greenlets instead of threads. Think of Greenlets as ultra-lightweight &quot;pseudo-threads&quot; that share the same OS thread. Instead of the operating system deciding when to switch between them (&lt;span x-data=&quot;&quot; x-tooltip.raw=&quot;Operating system forcibly switches between tasks at any time, regardless of whether the task is ready to yield control&quot;&gt; preemptive multitasking &lt;/span&gt;), Greenlets explicitly &lt;strong&gt;yield control&lt;/strong&gt; to each other (&lt;span x-data=&quot;&quot; x-tooltip.raw=&quot;Tasks voluntarily yield control to each other; each task must explicitly give up CPU time for others to run&quot;&gt; cooperative multitasking &lt;/span&gt;).&lt;/p&gt;
&lt;p&gt;Before talking about the actual fix, let&apos;s revisit our server configuration.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I had a Gevent-WSGI server and a single threaded Flask web application.&lt;/li&gt;
&lt;li&gt;Under load, the WSGI server was able to accept multiple requests thanks to the Gevent event loop.&lt;/li&gt;
&lt;li&gt;Every time a new request came, Gevent spawned a new greenlet.&lt;/li&gt;
&lt;li&gt;However, since the Flask application was still single-threaded, it didn&apos;t know about Gevent&apos;s event loop or Greenlets. It still processed requests sequentially and blocked on I/O calls like &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;requests.get&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;That meant no two Greenlets were able to call Flask simultaneously.&lt;/li&gt;
&lt;li&gt;This was evident from the memory charts (which spiked due to Greenlets in memory) and timeout errors we saw in clients (Greenlets were not able to process requests).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&apos;s where I messed up. I completely missed replacing Python&apos;s standard blocking I/O with &lt;span&gt; Gevent-compatible versions &lt;/span&gt; during the development phase.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;python&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;python&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;from&lt;/span&gt; gevent import monkey
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;monkey.patch_all()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The above code &lt;span x-data=&quot;&quot; x-tooltip.raw=&quot;Replaces Python&amp;#x27;s standard library functions at runtime with Gevent&amp;#x27;s non-blocking equivalents&quot;&gt; replaces Python&apos;s standard library at runtime &lt;/span&gt;. After it runs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;import socket&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; → You get Gevent&apos;s socket (non-blocking)&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;import ssl&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; → You get Gevent&apos;s ssl (yields during handshake)&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;time.sleep()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; → Yields to event loop instead of blocking&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;threading.Thread&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; → Actually creates Greenlets, not threads&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&apos;s like swapping out the engine of a car while it&apos;s running. Sounds crazy, but it works.&lt;/p&gt;
&lt;p&gt;This is what I earlier had in my &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;main.py&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;python&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;python&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# No monkey patching here!&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;from&lt;/span&gt; gevent.pywsgi import WSGIServer
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;from&lt;/span&gt; flask import Flask, jsonify
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; requests
 
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;EXTERNAL_API&lt;/span&gt; = &quot;https://api.example.com/send-email&quot;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;app &lt;/span&gt;= Flask(__name__)
 
&lt;span style=&quot;--shiki-dark:#DCBDFB;--shiki-light:#6F42C1&quot;&gt;@app.route&lt;/span&gt;(&apos;/&apos;, methods=[&apos;POST&apos;])
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;def&lt;/span&gt; send_email():
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    payload &lt;/span&gt;= {}
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    # Makes HTTP call to external API&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    response &lt;/span&gt;= requests.post(EXTERNAL_API, json=payload)
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    return&lt;/span&gt; jsonify({&quot;status&quot;: &quot;sent&quot;}), 200
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Fire up the server&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;server &lt;/span&gt;= WSGIServer((&quot;0.0.0.0&quot;, 9876), app)
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;server.serve_forever()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;I was using WSGI from Gevent, so I thought I was good. Here&apos;s what actually happened when two requests arrived:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Request A arrives:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Flask starts processing&lt;/li&gt;
&lt;li&gt;Calls &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;requests.post()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to external API&lt;/li&gt;
&lt;li&gt;&lt;span&gt; BLOCKS on socket.send() &lt;/span&gt; (using
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;stdlib&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; socket!)&lt;/li&gt;
&lt;li&gt;Entire server frozen for 500ms&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Request B arrives while A is blocked:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Connection accepted by Gevent&lt;/li&gt;
&lt;li&gt;Request read into memory&lt;/li&gt;
&lt;li&gt;Queued for processing (greenlet created!)&lt;/li&gt;
&lt;li&gt;But it is stuck waiting because A&apos;s greenlet won&apos;t yield&lt;/li&gt;
&lt;/ul&gt;
&lt;figure data-astro-cid-s57xbq3y=&quot;&quot;&gt; &lt;div data-excalidraw-svg=&quot;&quot; data-astro-cid-s57xbq3y=&quot;&quot;&gt; &lt;img src=&quot;https://yashagarwal.in/_astro/request-processing-without-monkey-patching.CfoKxhdl.svg&quot; alt=&quot;Request processing without monkey patching - showing how requests queue up when Flask blocks on I/O&quot; data-astro-cid-s57xbq3y=&quot;&quot;&gt; &lt;/div&gt; &lt;figcaption data-astro-cid-s57xbq3y=&quot;&quot;&gt;Request processing without monkey patching: Request B waits in queue while Request A blocks the entire server&lt;/figcaption&gt; &lt;/figure&gt;  
&lt;p&gt;WSGI Server handles connection acceptance using Gevent&apos;s non-blocking event loop. But once the request reaches the Flask code and encounters a &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;requests.post()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, that uses the standard library socket, which blocks the entire greenlet.&lt;/p&gt;
&lt;p&gt;Since there&apos;s only one OS thread and A&apos;s greenlet is blocked (not yielding), B&apos;s greenlet never gets a chance to run. It&apos;s like having an async server with a synchronous bottleneck.&lt;/p&gt;
&lt;p&gt;This is the most non-trivial aspect of Gevent, and it caught me completely off-guard.&lt;/p&gt;
&lt;p&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;gevent.WSGIServer&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; can accept connections without monkey patching because &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;accept()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; uses Gevent&apos;s own event loop. So from the outside, it looks like your server is working. But then your application code blocks on &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;stdlib&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; I/O, and everything grinds to a halt.&lt;/p&gt;
&lt;p&gt;Everything looked &quot;normal&quot; on the server side because the requests that did process completed in reasonable time. The problem was all the other requests timing out in the queue, which the metrics didn&apos;t capture.&lt;/p&gt;
&lt;h1 id=&quot;how-i-fixed-it&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#how-i-fixed-it&quot;&gt;How I fixed it&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Adding just two lines of code fixed the issue. However, placement is critical. The monkey patching MUST happen before any other imports. Here&apos;s the proper way:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Add at the very top in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;main.py&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;python&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;python&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;from&lt;/span&gt; gevent import monkey
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;monkey.patch_all()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The difference between &quot;using Gevent&quot; and &quot;using Gevent correctly&quot; was a single import statement that I had forgotten to add when setting up the service months earlier.&lt;/p&gt;
&lt;h1 id=&quot;the-results&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-results&quot;&gt;The Results&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;After deploying the monkey patch fix to production:&lt;/p&gt;















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Metric&lt;/th&gt;&lt;th&gt;Before&lt;/th&gt;&lt;th&gt;After&lt;/th&gt;&lt;th&gt;Improvement&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;P95 Latency&lt;/td&gt;&lt;td&gt;~8-10s&lt;/td&gt;&lt;td&gt;&lt;span&gt; ~500ms &lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span&gt; 15x faster &lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Request Timeout Rate&lt;/td&gt;&lt;td&gt;~30%&lt;/td&gt;&lt;td&gt;&lt;span&gt; &amp;#x3C; 0.1% &lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span&gt; 300x reduction &lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Memory Usage&lt;/td&gt;&lt;td&gt;85% (growing)&lt;/td&gt;&lt;td&gt;&lt;span&gt; 50% (stable) &lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span&gt; Stabilized &lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Client Retry Attempts&lt;/td&gt;&lt;td&gt;15-17 per request&lt;/td&gt;&lt;td&gt;&lt;span&gt; 0 &lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span&gt; Eliminated &lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Email Service Load&lt;/td&gt;&lt;td&gt;700 req/min&lt;/td&gt;&lt;td&gt;&lt;span&gt; 30 req/min &lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span&gt; Back to normal &lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Requests processed&lt;/td&gt;&lt;td&gt;2000 req/sec&lt;/td&gt;&lt;td&gt;&lt;span&gt; 50 req/sec &lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span&gt; no retries anymore &lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The fix went live during a low-traffic window. Within 15 minutes, timeout errors dropped to near-zero.&lt;/p&gt;
&lt;p&gt;All services immediately showed the significant impact of the fix. Once new pods came up, they didn&apos;t show the earlier trend of steady memory increase. Memory usage remained consistent for several days after the fix. Request latency also dropped significantly since the email service was no longer overwhelmed with duplicate requests.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/notification-service-request-throughput.BWH3NZSH_Z1qOzRK.webp&quot; alt=&quot;Request Throughput&quot; title=&quot;Graph showing dramatic drop in request throughput after monkey patch fix was deployed.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2912&quot; height=&quot;1440&quot;&gt;
&lt;img src=&quot;https://yashagarwal.in/_astro/notification-service-http-latency.I__FUdiC_Z1IH7VP.webp&quot; alt=&quot;Request Latency&quot; title=&quot;Graph showing significant drop in latency.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2912&quot; height=&quot;1440&quot;&gt;&lt;/p&gt;
&lt;p&gt;Email service incoming request rate also showed a similar trend.
&lt;img src=&quot;https://yashagarwal.in/_astro/emailservice-api-request-rate.g2uLJkZn_Z2volXb.webp&quot; alt=&quot;Email service Incoming&quot; title=&quot;Email service incoming request rate.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2912&quot; height=&quot;1440&quot;&gt;&lt;/p&gt;
&lt;p&gt;Lastly, the memory usage pattern of the Flask pods stabilized completely. The HPA bug I found earlier was also fixed during this deployment. The pods no longer showed increasing memory usage over time.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/flask-pod-memory-pattern.DYxPyDPp_2sW2lJ.webp&quot; alt=&quot;Memory usage&quot; title=&quot;Memory usage pattern stabilized after fix.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2752&quot; height=&quot;1536&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;what-i-learned&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#what-i-learned&quot;&gt;What I Learned&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This bug taught me that understanding your framework&apos;s internals isn&apos;t optional – it&apos;s essential. I thought I was using Gevent because I imported &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;gevent.pywsgi&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. I wasn&apos;t. I was using Gevent&apos;s connection handling with Python&apos;s blocking I/O, getting the worst of both worlds.&lt;/p&gt;
&lt;p&gt;The three biggest lessons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Read the docs thoroughly&lt;/strong&gt; - Gevent&apos;s &lt;a href=&quot;https://www.gevent.org/intro.html#monkey-patching&quot;&gt;documentation&lt;/a&gt; mentions monkey patching on the first page. I skimmed it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Question your metrics&lt;/strong&gt; - When client and server metrics don&apos;t match, dig deeper.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Distributed tracing is your friend&lt;/strong&gt; - Missing server spans pointed directly to the problem.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The fix was embarrassingly simple. The debugging was not. But that&apos;s software engineering – sometimes the smallest oversights create the biggest problems.&lt;/p&gt;
&lt;p&gt;And now I have a great story for &quot;Tell me about a time you debugged a tricky production issue&quot; question during interviews.&lt;/p&gt;</content:encoded></item><item><title>Making RedBeat Work with Redis Sentinel Username Auth</title><link>https://yashagarwal.in/notes/making-redbeat-work-with-redis-sentinel-username-auth/</link><guid isPermaLink="true">https://yashagarwal.in/notes/making-redbeat-work-with-redis-sentinel-username-auth/</guid><description>A deep dive into solving RedBeat&apos;s Redis Sentinel username authentication limitation through a configuration workaround.</description><pubDate>Thu, 23 Oct 2025 16:05:00 GMT</pubDate><content:encoded>&lt;p&gt;A few weeks ago, while working on a new microservice at work, I encountered an interesting authentication issue with Celery&apos;s RedBeat scheduler when connecting to Redis Sentinel with username-based authentication. What seemed like a simple configuration problem turned out to be a non-trivial limitation in RedBeat&apos;s implementation. This post documents the problem, the solution, and why it matters.&lt;/p&gt;
&lt;h1 id=&quot;the-setup&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-setup&quot;&gt;The Setup&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Our application stack includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Celery&lt;/strong&gt; for distributed task processing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RedBeat&lt;/strong&gt; as our dynamic Beat scheduler&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redis Sentinel&lt;/strong&gt; for high availability&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redis ACL&lt;/strong&gt; for username/password authentication&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sibson/redbeat&quot;&gt;RedBeat&lt;/a&gt; is fantastic for managing dynamic schedules - you can add or modify tasks without restarting the beat process. Redis Sentinel adds high availability by automatically handling failovers when the master goes down. Both work beautifully in isolation, but combining them with Redis ACL authentication revealed an unexpected gap.&lt;/p&gt;
&lt;h1 id=&quot;the-problem&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-problem&quot;&gt;The Problem&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Modern Redis deployments use ACL (Access Control Lists) that require both username and password for authentication. However, when I tried to start RedBeat with Sentinel, I kept getting authentication errors:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;redis.exceptions.AuthenticationError: WRONGPASS invalid username-password pair or user is disabled.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;At first, I thought it was a configuration mistake on my end. I double-checked credentials, verified Sentinel configuration, and confirmed that the username/password combination worked perfectly when connecting directly to Redis. Everything seemed correct.&lt;/p&gt;
&lt;p&gt;Eventually, after digging through RedBeat&apos;s source code, I found the issue. When RedBeat &lt;a href=&quot;https://github.com/sibson/redbeat/blob/b5df9bfb766b2011376aec00c84d9449cede422d/redbeat/schedulers.py#L138&quot;&gt;initializes&lt;/a&gt; its Sentinel client in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;get_redis()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; function, it only passes specific authentication parameters:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;python&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;python&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# From RedBeat&apos;s get_redis() function&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;elif&lt;/span&gt; conf.redis_url.startswith(&apos;redis-sentinel&apos;) and &apos;sentinels&apos; in redis_options:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    connection_kwargs &lt;/span&gt;= {}
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    if&lt;/span&gt; isinstance(conf.redis_use_ssl, dict):
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        connection_kwargs[&lt;/span&gt;&apos;ssl&apos;] = True
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        connection_kwargs.update(conf.redis_use_ssl)&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    sentinel &lt;/span&gt;= Sentinel(
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        redis_options[&lt;/span&gt;&apos;sentinels&apos;],
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;        socket_timeout&lt;/span&gt;=redis_options.get(&apos;socket_timeout&apos;),
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;        password&lt;/span&gt;=redis_options.get(&apos;password&apos;),  # ⚠️ Only password
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;        db&lt;/span&gt;=redis_options.get(&apos;db&apos;, 0),
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;        decode_responses&lt;/span&gt;=True,
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;        sentinel_kwargs&lt;/span&gt;=redis_options.get(&apos;sentinel_kwargs&apos;),
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;        **&lt;/span&gt;connection_kwargs,  # SSL options spread here
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    )&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Notice the missing &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;username&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; parameter? RedBeat explicitly extracts &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;password&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; from &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;redis_options&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and pass it to the Sentinel object, but there&apos;s no corresponding username extraction. This isn&apos;t a bug per se - it&apos;s a limitation. The underlying &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;redis-py&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; library fully supports username authentication, and Celery&apos;s Redis transport handles it fine. RedBeat simply doesn&apos;t expose this capability for Sentinel connections.&lt;/p&gt;
&lt;h1 id=&quot;why-this-is-non-trivial&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#why-this-is-non-trivial&quot;&gt;Why This is Non-Trivial&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This problem sits at an interesting intersection:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Architectural Complexity&lt;/strong&gt;: Redis Sentinel architecture has two types of connections - connections to Sentinel instances for service discovery, and connections to the actual Redis master for data operations. Both need authentication with ACL enabled.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;No Direct Configuration&lt;/strong&gt;: RedBeat doesn&apos;t provide a &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;redbeat_redis_username&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; option or similar. The standard approaches don&apos;t work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Can&apos;t pass username in the URL (RedBeat uses a custom &lt;a href=&quot;https://redbeat.readthedocs.io/en/latest/config.html#sentinel-support&quot;&gt;Sentinel URL&lt;/a&gt; format)&lt;/li&gt;
&lt;li&gt;Can&apos;t modify &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sentinel_kwargs&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; from configuration (it&apos;s hardcoded)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Security Constraints&lt;/strong&gt;: Our production Redis deployments require ACL authentication. The default user is disabled, and password-only auth is not allowed. Downgrading security wasn&apos;t an option.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;the-workaround&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-workaround&quot;&gt;The Workaround&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;After studying RedBeat&apos;s code more carefully, I noticed something crucial. Look at the Sentinel initialization code again:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;python&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;python&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;connection_kwargs &lt;/span&gt;= {}
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;if&lt;/span&gt; isinstance(conf.redis_use_ssl, dict):
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    connection_kwargs[&lt;/span&gt;&apos;ssl&apos;] = True
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    connection_kwargs.update(conf.redis_use_ssl)  &lt;/span&gt;# ← Key line!
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;sentinel &lt;/span&gt;= Sentinel(
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    redis_options[&lt;/span&gt;&apos;sentinels&apos;],
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    # ... other explicit parameters ...&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    **&lt;/span&gt;connection_kwargs,  # ← This spreads our dict!
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;redis_use_ssl&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; configuration (which maps to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;redbeat_redis_use_ssl&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; in &lt;a href=&quot;https://redbeat.readthedocs.io/en/latest/config.html#redbeat-redis-use-ssl&quot;&gt;Celery config&lt;/a&gt;) gets unpacked directly into the Sentinel constructor via &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;**connection_kwargs&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. This happens &lt;em&gt;after&lt;/em&gt; all the explicit parameters are set, which means anything in that dictionary gets passed through to the Sentinel client.&lt;/p&gt;
&lt;p&gt;This is our injection point. Since the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;redis-py&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; Sentinel class accepts &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;username&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; as a parameter, we can smuggle it through this SSL configuration dictionary. Here&apos;s how I leveraged this:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;python&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;python&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;def&lt;/span&gt; setup_redis_sentinel_config(app_config, sentinel_nodes, auth_info):
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    &quot;&quot;&quot;&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    Configure Celery and RedBeat for authenticated Sentinel connections.&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    Args:&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        app_config: Main application configuration dict&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        sentinel_nodes: List of (host, port) tuples for Sentinel nodes&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        auth_info: Dict containing &apos;username&apos; and &apos;password&apos;&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    &quot;&quot;&quot;&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    service_name &lt;/span&gt;= &quot;myredis-master&quot;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    # Configure Celery&apos;s broker and backend&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    app_config.broker_url &lt;/span&gt;= f&quot;sentinel://localhost:26379&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    app_config.result_backend &lt;/span&gt;= f&quot;sentinel://localhost:26379&quot;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    # Celery&apos;s broker transport handles its own auth correctly&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    app_config.broker_transport_options &lt;/span&gt;= {
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        &quot;master_name&quot;&lt;/span&gt;: service_name,
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        &quot;sentinels&quot;&lt;/span&gt;: sentinel_nodes,
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        &quot;sentinel_kwargs&quot;&lt;/span&gt;: {&quot;password&quot;: None},  # Sentinels don&apos;t need auth
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        &quot;username&quot;&lt;/span&gt;: auth_info[&quot;username&quot;],
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        &quot;password&quot;&lt;/span&gt;: auth_info[&quot;password&quot;],
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    }&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    # RedBeat&apos;s standard config for master connections&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    app_config.redbeat_redis_url &lt;/span&gt;= &quot;redis-sentinel://&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    app_config.redbeat_redis_options &lt;/span&gt;= {
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        &quot;sentinels&quot;&lt;/span&gt;: sentinel_nodes,
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        &quot;service_name&quot;&lt;/span&gt;: service_name,
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        &quot;db&quot;&lt;/span&gt;: 0,
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        &quot;sentinel_kwargs&quot;&lt;/span&gt;: {&quot;password&quot;: None},
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        &quot;password&quot;&lt;/span&gt;: auth_info[&quot;password&quot;],
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    }&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    # THE WORKAROUND: Piggyback on redis_use_ssl to inject username&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    # RedBeat unpacks this dict into connection_kwargs which gets spread&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    # into the Sentinel constructor, bypassing RedBeat&apos;s parameter filtering&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    app_config.redbeat_redis_use_ssl &lt;/span&gt;= {
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        &quot;username&quot;&lt;/span&gt;: auth_info[&quot;username&quot;],
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        &quot;ssl&quot;&lt;/span&gt;: False,  # Critical: prevent actual SSL from being enabled
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    }&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    return&lt;/span&gt; app_config&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The beauty of this approach is that &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;redbeat_redis_use_ssl&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; skips RedBeat&apos;s normal parameter validation. The dictionary contents get unpacked via &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;**connection_kwargs&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; directly into &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Sentinel()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, allowing us to pass the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;username&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; parameter that RedBeat&apos;s explicit parameter list ignores.&lt;/p&gt;
&lt;p&gt;Setting &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;ssl=False&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is crucial - even though RedBeat sets &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;connection_kwargs[&apos;ssl&apos;] = True&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; when it detects the config, our explicit &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;False&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; in the spread dict takes precedence.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This experience demonstrates that production systems often require creative solutions when dealing with the intersection of multiple technologies. Sometimes the &quot;right&quot; answer isn&apos;t about writing new code, but about understanding existing code well enough to work within its constraints.&lt;/p&gt;
&lt;p&gt;If you&apos;re facing similar issues with RedBeat and Redis Sentinel authentication, I hope this helps. And if you maintain a Celery-based application, this might be a good time to check whether your authentication setup is future-proof for ACL-based Redis deployments.&lt;/p&gt;</content:encoded></item><item><title>Setting Up Disqus in a Next.js Blog</title><link>https://yashagarwal.in/notes/setting-up-disqus-in-nextjs-blog/</link><guid isPermaLink="true">https://yashagarwal.in/notes/setting-up-disqus-in-nextjs-blog/</guid><description>Integrate Disqus comments into your Next.js blog with dark mode support. Learn lazy loading and resolve color compatibility for a seamless user experience.</description><pubDate>Wed, 28 May 2025 11:13:24 GMT</pubDate><content:encoded>&lt;p&gt;Disqus is the most popular commenting system available in the market right now. While its free nature comes with downsides (&lt;em&gt;hint&lt;/em&gt; - you are the data!), its ease of setup and not having to maintain a self-hosted commenting solution makes it a compelling choice for small blogs like this one.&lt;/p&gt;
&lt;p&gt;I have been using Disqus for the last 10 years across various static site generators, so it contains all of my previous comments. While migrating Disqus comments to a different URL scheme is a topic for another day, this article focuses on setting up Disqus in a Next.js blog.&lt;/p&gt;
&lt;p&gt;We&apos;ll cover how to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a React component wrapper for Disqus&lt;/li&gt;
&lt;li&gt;Implement lazy loading when the component is in view&lt;/li&gt;
&lt;li&gt;Make Disqus respect theme toggling&lt;/li&gt;
&lt;li&gt;Resolve OKLCH color incompatibility issues&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Without further ado, let&apos;s begin.&lt;/p&gt;
&lt;h1 id=&quot;prerequisites&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;You should have a Next.js blog.&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;next-themes&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; for handling the dark mode toggling.&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;disqus-react&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; for providing Disqus script.&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;react-intersection-observer&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to implement lazy-loading.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;getting-your-disqus-shortname&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#getting-your-disqus-shortname&quot;&gt;Getting Your Disqus Shortname&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Before implementing the component, you&apos;ll need to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a Disqus account at &lt;a href=&quot;https://disqus.com/&quot;&gt;disqus.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Register your site and get your shortname&lt;/li&gt;
&lt;li&gt;Configure your site settings in the Disqus admin panel&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;install-the-required-packages&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#install-the-required-packages&quot;&gt;Install the required packages&lt;/a&gt;&lt;/h1&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;npm&lt;/span&gt; install disqus-react next-themes react-intersection-observer
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# OR&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;bun&lt;/span&gt; add disqus-react next-themes react-intersection-observer&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;setting-up-next-themes&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#setting-up-next-themes&quot;&gt;Setting up next-themes&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Adapt the root layout to match the following snippet -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;tsx&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;tsx&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; { ThemeProvider } from &quot;next-themes&quot;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; &quot;./globals.css&quot;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;interface&lt;/span&gt; RootLayoutProps {
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;  children&lt;/span&gt;: React.ReactNode
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;export&lt;/span&gt; default function RootLayout({ children }: RootLayoutProps) {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  return&lt;/span&gt; (
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;html lang=&quot;en&quot; suppressHydrationWarning&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      &amp;#x3C;&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        &amp;#x3C;&lt;/span&gt;ThemeProvider
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;          attribute&lt;/span&gt;=&quot;class&quot;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;          defaultTheme&lt;/span&gt;=&quot;system&quot;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;          enableSystem&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;          disableTransitionOnChange&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        &gt;&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#24292E&quot;&gt;          {&lt;/span&gt;children}
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        &amp;#x3C;/&lt;/span&gt;ThemeProvider&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      &amp;#x3C;/&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;/&lt;/span&gt;html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  )&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now add the following to the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;globals.css&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;css&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;css&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;@import&lt;/span&gt; &quot;tailwindcss&quot;;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;@config&lt;/span&gt; &quot;../tailwind.config.js&quot;;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;@layer&lt;/span&gt; base {
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;  :root&lt;/span&gt; {
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;    --background&lt;/span&gt;: theme(&quot;colors.white&quot;);
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;    --foreground&lt;/span&gt;: theme(&quot;colors.slate.950&quot;);
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  }&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;  .dark&lt;/span&gt; {
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;    --background&lt;/span&gt;: theme(&quot;colors.slate.950&quot;);
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;    --foreground&lt;/span&gt;: theme(&quot;colors.slate.50&quot;);
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  }&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  body&lt;/span&gt; {
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    @&lt;/span&gt;apply bg-background text-foreground;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;    transition&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      background-color &lt;/span&gt;0.2s ease,
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;      color&lt;/span&gt; 0.2s ease;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Key features of this setup:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;suppressHydrationWarning&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;: Prevents hydration warnings when theme changes on client&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;attribute=&quot;class&quot;&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;: Uses CSS classes for theme switching (&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;.dark&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; class)&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;defaultTheme=&quot;system&quot;&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;: Respects user&apos;s system preference&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;enableSystem&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;: Allows automatic system theme detection&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;disableTransitionOnChange&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;: Prevents flash during theme transitions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since I use TailwindCSS v4, the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;globals.css&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; might look a bit different. Another important thing to note is the use of syntax like &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;theme(&quot;colors.slate.950&quot;)&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; for setting the colors. This doesn&apos;t play nice with Disqus. We will see how to fix it later.&lt;/p&gt;
&lt;h1 id=&quot;disqus-component&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#disqus-component&quot;&gt;Disqus Component&lt;/a&gt;&lt;/h1&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;tsx&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;tsx&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;&quot;use client&quot;&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; React from &quot;react&quot;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; { DiscussionEmbed } from &quot;disqus-react&quot;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; { useTheme } from &quot;next-themes&quot;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; { useInView } from &quot;react-intersection-observer&quot;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;interface&lt;/span&gt; CommentProps {
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;  url&lt;/span&gt;: string
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;  slug&lt;/span&gt;: string
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;export&lt;/span&gt; const DisqusComments = ({ url, slug }: CommentProps) =&gt; {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  const&lt;/span&gt; { resolvedTheme = &quot;light&quot; } = useTheme()
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  const&lt;/span&gt; { ref, inView } = useInView({
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    threshold: &lt;/span&gt;0,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    triggerOnce: &lt;/span&gt;true,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    fallbackInView: &lt;/span&gt;true,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  })&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  const&lt;/span&gt; disqusShortname = &quot;your-disqus-shortname-here&quot;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  const&lt;/span&gt; disqusConfig = {
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    identifier: slug,&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    url: url,&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  }&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  return&lt;/span&gt; (
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;div ref={ref}&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#24292E&quot;&gt;      {&lt;/span&gt;inView ? (
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        &amp;#x3C;&lt;/span&gt;div className=&quot;comments&quot;&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;          &amp;#x3C;&lt;/span&gt;DiscussionEmbed
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;            key&lt;/span&gt;={resolvedTheme}
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;            shortname&lt;/span&gt;={disqusShortname}
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;            config&lt;/span&gt;={disqusConfig}
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;          /&gt;&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        &amp;#x3C;/&lt;/span&gt;div&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      ) &lt;/span&gt;: null}
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;/&lt;/span&gt;div&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  )&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Key Features of this component are -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Lazy Loading with Intersection Observer&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The component uses &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;react-intersection-observer&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to implement lazy loading:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Comments only load when the user scrolls to the comments section.&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;threshold: 0&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; triggers loading as soon as the element enters the viewport.&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;triggerOnce: true&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; ensures the component only loads once.&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;fallbackInView: true&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; provides a fallback for environments where IntersectionObserver isn&apos;t available.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Theme-Aware Rendering&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The most crucial aspect for dark mode support is the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;key={resolvedTheme}&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; prop on the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;DiscussionEmbed&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; component. This forces React to completely remount the Disqus embed whenever the theme changes, ensuring proper color adaptation.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;using-the-disqus-component&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#using-the-disqus-component&quot;&gt;Using the Disqus component&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The component is used in the blog note page &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;app/notes/[slug]/page.tsx&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; (such as this one):&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;tsx&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;tsx&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;DisqusComments
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;  slug&lt;/span&gt;={params.slug}
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;  url&lt;/span&gt;={`${siteConfig.url}/notes/${params.slug}`}
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;/&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The URL construction ensures each post has a unique identifier for Disqus threads, while the slug provides a fallback identifier.&lt;/p&gt;
&lt;h1 id=&quot;fixing-oklch-color-incompatibility&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#fixing-oklch-color-incompatibility&quot;&gt;Fixing OKLCH Color Incompatibility&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Modern CSS frameworks like Tailwind CSS v4 use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch&quot;&gt;OKLCH&lt;/a&gt; colors for better color accuracy and perceptual uniformity. However, Disqus&apos;s embedded iframe doesn&apos;t understand OKLCH color values.&lt;/p&gt;
&lt;p&gt;When OKLCH colors are used, you&apos;ll encounter this error in the browser console:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;js&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;js&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;Uncaught &lt;/span&gt;Error: parseColor received unparseable color: oklch(000)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/parseColor-error.BG2HAORn_2ufFpp.webp&quot; alt=&quot;parseColor Error&quot; title=&quot;parseColor error in console&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1356&quot; height=&quot;262&quot;&gt;&lt;/p&gt;
&lt;p&gt;This happens because Disqus validates color values and expects them to be in RGB or Hex format.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/disqus-code-ref.CRZjvPAO_Z1mIWPM.webp&quot; alt=&quot;Disqus code checks for RGB/Hex&quot; title=&quot;Disqus code checks for RGB/Hex&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1590&quot; height=&quot;1430&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-solution&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-solution&quot;&gt;The Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Override OKLCH colors with Hex equivalents specifically for the Disqus container:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;css&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;css&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;/* Fix for https://github.com/disqus/disqus-react/issues/153 */&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;:root&lt;/span&gt;,
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;.comments&lt;/span&gt; {
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;  background-color&lt;/span&gt;: #ffffff !important; /* white */
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;  color&lt;/span&gt;: #0f172a !important; /* slate-950 */
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;/* Dark mode comments - using hex values */&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;:root&lt;/span&gt;,
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;.dark&lt;/span&gt; .comments {
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;  background-color&lt;/span&gt;: #020617 !important; /* slate-950 */
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;  color&lt;/span&gt;: #f8fafc !important; /* slate-50 */
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;performance-considerations&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#performance-considerations&quot;&gt;Performance Considerations&lt;/a&gt;&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lazy Loading&lt;/strong&gt;: Comments only load when visible, reducing initial page load time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Theme Remounting&lt;/strong&gt;: While remounting on theme change might seem expensive, it&apos;s necessary for proper theme switching and happens infrequently.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CSS Optimization&lt;/strong&gt;: Color fixes are applied at the CSS level, avoiding JavaScript-based solutions that could impact performance.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Migrating from Contentlayer to Content-Collections</title><link>https://yashagarwal.in/notes/contentlayer-to-content-collections/</link><guid isPermaLink="true">https://yashagarwal.in/notes/contentlayer-to-content-collections/</guid><description>Explore the migration process from Contentlayer to content-collections for a Next.js blog, detailing configuration and MDX pipeline changes.</description><pubDate>Sun, 25 May 2025 11:47:24 GMT</pubDate><content:encoded>&lt;p&gt;When I &lt;a href=&quot;https://yashagarwal.in/notes/how-i-built-a-blog-with-nextjs&quot;&gt;first&lt;/a&gt; moved my blog&apos;s tech stack to Next.js, &lt;a href=&quot;https://contentlayer.dev/&quot;&gt;Contentlayer&lt;/a&gt; was a rage. Obviously, I also &lt;a href=&quot;https://yashagarwal.in/notes/integrating-contentlayer-with-nextjs-blog&quot;&gt;decided&lt;/a&gt; to use it for managing the content here. However, over time, Contentlayer stopped getting updates, and eventually the creator &lt;a href=&quot;https://github.com/contentlayerdev/contentlayer/issues/429&quot;&gt;declared&lt;/a&gt; their inability to continue its development. Keeping the package version pinned allowed me to avoid any issues for almost a year. Last year, when &lt;a href=&quot;https://nextjs.org/blog/next-15&quot;&gt;Next.js 15&lt;/a&gt; dropped, I tried to update my blog to it, but due to Contentlayer&apos;s peer dependencies, the update failed. Finally, a few days back, I decided to put in some effort to do the migration. I had two primary choices - &lt;a href=&quot;https://github.com/timlrx/contentlayer2&quot;&gt;Contentlayer2&lt;/a&gt; and &lt;a href=&quot;https://www.content-collections.dev/&quot;&gt;content-collections&lt;/a&gt;. While Contentlayer2 would have been a straightforward migration, I decided to go with content-collections, simply because it seems a &lt;a href=&quot;https://sdorra.dev/posts/2024-01-15-content-collections&quot;&gt;better tool&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The migration mostly went smoothly, apart from a few hiccups. I figured I&apos;d document my thoughts and the steps I took, primarily as a note to myself for when I inevitably forget the implementation details.&lt;/p&gt;
&lt;p&gt;If you are more of a code reader, then here is the &lt;a href=&quot;https://github.com/yashhere/yashagarwal.in/pull/103&quot;&gt;PR&lt;/a&gt; for reference.&lt;/p&gt;
&lt;h2 id=&quot;why-the-switch&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#why-the-switch&quot;&gt;Why the Switch?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With Contentlayer, it was pretty straightforward to get MDX content integrated into my Next.js site. However, its development has almost stalled due to lack of funding, or at least not as active as I&apos;d hoped in the long run.&lt;/p&gt;
&lt;p&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;content-collections&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; caught my eye as a more modern and arguably more flexible alternative. It promises similar developer experience while providing a more robust and actively maintained foundation with finer-grained control over the content pipeline. I was particularly drawn to how content-collections structures its transformations and schema definitions. This approach would give me more power to shape my content exactly as needed without fighting the tooling. Though I don&apos;t currently need many of its advanced capabilities, having them available for future use is valuable.&lt;/p&gt;
&lt;h2 id=&quot;the-migration-journey&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-migration-journey&quot;&gt;The Migration Journey&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This wasn&apos;t just a find-and-replace operation; it required understanding how my content was processed and rendered by the Contentlayer pipeline.&lt;/p&gt;
&lt;h3 id=&quot;1-configuration-overhaul&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#1-configuration-overhaul&quot;&gt;1. Configuration Overhaul&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The biggest chunk of work was defining my content collections. Instead of the Contentlayer functions &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;defineDocumentType&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;defineComputedFields&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, I&apos;m now using &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;defineCollection&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;defineConfig&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; from &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;@content-collections/core&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The filename changes too - &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;contentlayer.config.ts&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; -&gt; &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;content-collections.ts&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I replicated my &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;notes&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;lifelog&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; schemas, defining the fields (&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;title&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;createdOn&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;description&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;tags&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, etc.) using Zod for validation, which is a nice touch.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;typescript&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;typescript&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;// Old (contentlayer.config.ts - conceptually)&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;// export const Note = defineDocumentType(() =&gt; ({ ... }))&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;// New (content-collections.ts)&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;const&lt;/span&gt; notes = defineCollection({
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  name: &lt;/span&gt;&quot;notes&quot;,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  directory: &lt;/span&gt;&quot;content/notes&quot;,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  include: &lt;/span&gt;&quot;*.mdx&quot;,
&lt;span style=&quot;--shiki-dark:#DCBDFB;--shiki-light:#6F42C1&quot;&gt;  schema&lt;/span&gt;: (z) =&gt; ({
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    title: z.&lt;/span&gt;string(),
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    // ... rest of the schema&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  }),&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;  // ... transform function&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;})&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;export&lt;/span&gt; default defineConfig({
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  collections: [notes, lifelog]&lt;/span&gt;,
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#24292E&quot;&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This new config file, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;content-collections.ts&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, became the single source of truth for all my content definitions and processing logic.&lt;/p&gt;
&lt;h3 id=&quot;2-mdx-pipeline-reconstruction&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#2-mdx-pipeline-reconstruction&quot;&gt;2. MDX Pipeline Reconstruction&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This was where content-collections really showed its flexibility, and where I spent a fair bit of time re-wiring. Instead of Contentlayer&apos;s direct &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;mdx&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; configuration in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;makeSource&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, content-collections offers a &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;transform&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; function within each collection definition. This &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;transform&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; function provides significant flexibility.&lt;/p&gt;
&lt;p&gt;I now explicitly call &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;compileMDX&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; from &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;@content-collections/mdx&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; within the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;transform&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; function for both my &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;notes&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;lifelog&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; collections. This gave me direct access to the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;remark&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;rehype&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; plugin chains.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;typescript&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;typescript&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;// Inside transform function in content-collections.ts&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;const&lt;/span&gt; mdx = await compileMDX(context, document, {
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  rehypePlugins: [&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    // ... my rehype plugins like rehypeKatex, rehypePrettyCode, rehypeAutolinkHeadings&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  ],&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  remarkPlugins: [&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    // ... my remark plugins like remarkGfm, remarkMath, remarkCallouts, remarkWikiLink&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  ],&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;})&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;return&lt;/span&gt; {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  ...&lt;/span&gt;document,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  mdx, &lt;/span&gt;// The compiled MDX code is now available on `document.mdx`
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;  // ... other computed fields&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This setup also allowed me to explicitly handle custom logic for &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;readingTime&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;headings&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; extraction right within the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;transform&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; function, rather than relying on Contentlayer&apos;s &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;computedFields&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Crucially, the compiled MDX content now lives under &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;document.mdx&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; instead of &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;document.body.code&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, which meant updating all my component usage.&lt;/p&gt;
&lt;h3 id=&quot;3-component--usage-updates&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#3-component--usage-updates&quot;&gt;3. Component &amp;#x26; Usage Updates&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This was mostly a global find-and-replace, but important nonetheless:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Imports&lt;/strong&gt;: All instances of &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;contentlayer/generated&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; were updated to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;content-collections&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MDX Rendering&lt;/strong&gt;: My &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;MDX&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; component underwent a significant change.
&lt;ul&gt;
&lt;li&gt;The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;getMDXComponent&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; from &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;next-contentlayer/hooks&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; was replaced by &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;useMDXComponent&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; from &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;@content-collections/mdx/react&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;My &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;CustomMDXComponents&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; (now just &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;components&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; internally) are passed directly to the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Component&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; rendered by &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;useMDXComponent&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;Anywhere I was using &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;note.body.code&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, I switched to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;note.mdx&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Access&lt;/strong&gt;: In &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;lib/content.ts&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, I had to adjust how I accessed certain properties. For instance, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;doc._meta.path&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; became the new way to get the flattened path (what used to be &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;slug&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; for internal filtering), and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;doc.content&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; now holds the raw markdown, replacing &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;doc.body.raw&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. Even the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pick&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; utility function changed from &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;contentlayer/client&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;lodash&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;4-tooling-and-linting-adjustments&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#4-tooling-and-linting-adjustments&quot;&gt;4. Tooling and Linting Adjustments&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Follow official content-collections &lt;a href=&quot;https://www.content-collections.dev/docs/quickstart/next&quot;&gt;setup guide&lt;/a&gt; and &lt;a href=&quot;https://www.content-collections.dev/docs/migration/contentlayer&quot;&gt;migration guide&lt;/a&gt; for up-to-date information.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;.gitignore&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; &amp;#x26; &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;.prettierignore&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/strong&gt;: Updated to ignore &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;.content-collections&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; directory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;next.config.js&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/strong&gt;: Switched from &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;withContentlayer&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;withContentCollections&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;package.json&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/strong&gt;: Installed &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;content-collections&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; packages and tweaked the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;build&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; script (no more &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;contentlayer build&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; command needed explicitly, as &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;next build&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; now handles it through the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;withContentCollections&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; plugin). This is great since I don&apos;t have to run two commands in parallel now.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;tsconfig.json&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/strong&gt;: Adjusted the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;paths&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; alias for &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;contentlayer/generated&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;content-collections&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;hiccups-along-the-way&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#hiccups-along-the-way&quot;&gt;Hiccups Along the Way&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;No migration is completely smooth. I also encountered one significant challenge:&lt;/p&gt;
&lt;h3 id=&quot;1-code-block-styling-quirks&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#1-code-block-styling-quirks&quot;&gt;1. Code Block Styling Quirks&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The most noticeable friction came with &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;rehype-pretty-code&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and how it interacts with the HTML output in content-collections vs. Contentlayer. Since I updated the plugin to its latest version, the code block styling completely broke down. I think the newly generated HTML structure or the way it was injected seemed to have some subtle differences.&lt;/p&gt;
&lt;p&gt;My code blocks and inline code looked a bit off after the migration. Styles for line highlighting and character highlighting weren&apos;t applying correctly, and the general aesthetics of code blocks changed. I think this was more of a side-effect of updating the plugin &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;rehype-pretty-code&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and not due to the actual migration itself.&lt;/p&gt;
&lt;p&gt;I took this opportunity to refactor the styling a bit to make it simpler.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The selectors for &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;rehype-pretty-code&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; elements needed to be updated (e.g., from &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;[data-rehype-pretty-code-fragment]&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;figure[data-rehype-pretty-code-figure]&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;I also changed the rehype-pretty-code specific class names to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;line--highlighted&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;word--highlighted&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;reflections-and-takeaways&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#reflections-and-takeaways&quot;&gt;Reflections and Takeaways&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Overall, this migration was a fantastic learning experience. While the migration required several days of focused work, the benefits are tangible:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;More Control&lt;/strong&gt;: I appreciate the explicit &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;transform&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; function in content-collections. It feels like I have a clearer mental model of the content processing pipeline, which makes debugging and extending it much easier.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Active Development&lt;/strong&gt;: content-collections appears to be more actively maintained and evolving, which gives me more confidence in its long-term viability for my projects.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It was a good investment of time, and I&apos;m happy with the new content pipeline. Here&apos;s to more flexible content management and future blog articles!&lt;/p&gt;</content:encoded></item><item><title>Securing Traefik Docker Proxy</title><link>https://yashagarwal.in/notes/securing-traefik-with-ufw-fail2ban/</link><guid isPermaLink="true">https://yashagarwal.in/notes/securing-traefik-with-ufw-fail2ban/</guid><description>Learn to secure your Traefik Docker reverse proxy with a layered defense using UFW, Fail2Ban, and PSAD for robust server protection.</description><pubDate>Sat, 17 May 2025 03:35:47 GMT</pubDate><content:encoded>&lt;p&gt;When exposing a reverse proxy like &lt;a href=&quot;https://traefik.io/&quot;&gt;Traefik&lt;/a&gt; to the public internet, security should be a top priority. I recently deployed Traefik on a public-facing Linux server to route traffic to Docker containers - and I wanted a robust, layered security model to defend against port scans, brute-force attacks, and misbehaving clients.&lt;/p&gt;
&lt;p&gt;In this post, I’ll walk through how I secured my Traefik setup using UFW, Fail2Ban, and PSAD - combining firewall rules, intrusion detection, and log-based banning into an effective security stack.&lt;/p&gt;
&lt;h1 id=&quot;why-a-layered-security-model&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#why-a-layered-security-model&quot;&gt;Why a Layered Security Model?&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Each component of this stack plays a specific role:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;UFW:&lt;/strong&gt; Acts as our first line of defense by controlling which ports are exposed and accessible&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;iptables:&lt;/strong&gt; Powers UFW and handles low-level packet filtering; we&apos;ll also configure it directly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PSAD:&lt;/strong&gt; Monitors network traffic to detect and block potential intrusion attempts like port scans&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fail2Ban:&lt;/strong&gt; Analyzes application logs (Traefik in our case) to identify and block malicious behavior&lt;/li&gt;
&lt;/ul&gt;
&lt;svg id=&quot;mermaid-0&quot; width=&quot;100%&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; viewBox=&quot;0 0 1013.7421875 832.421875&quot; role=&quot;graphics-document document&quot; aria-roledescription=&quot;flowchart-v2&quot;&gt;&lt;g&gt;&lt;marker id=&quot;mermaid-0_flowchart-v2-pointEnd&quot; class=&quot;marker flowchart-v2&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;5&quot; refY=&quot;5&quot; markerUnits=&quot;userSpaceOnUse&quot; markerWidth=&quot;8&quot; markerHeight=&quot;8&quot; orient=&quot;auto&quot;&gt;&lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; class=&quot;arrowMarkerPath&quot; style=&quot;stroke-width:1;stroke-dasharray:1, 0&quot;&gt;&lt;/path&gt;&lt;/marker&gt;&lt;marker id=&quot;mermaid-0_flowchart-v2-pointStart&quot; class=&quot;marker flowchart-v2&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;4.5&quot; refY=&quot;5&quot; markerUnits=&quot;userSpaceOnUse&quot; markerWidth=&quot;8&quot; markerHeight=&quot;8&quot; orient=&quot;auto&quot;&gt;&lt;path d=&quot;M 0 5 L 10 10 L 10 0 z&quot; class=&quot;arrowMarkerPath&quot; style=&quot;stroke-width:1;stroke-dasharray:1, 0&quot;&gt;&lt;/path&gt;&lt;/marker&gt;&lt;marker id=&quot;mermaid-0_flowchart-v2-circleEnd&quot; class=&quot;marker flowchart-v2&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;11&quot; refY=&quot;5&quot; markerUnits=&quot;userSpaceOnUse&quot; markerWidth=&quot;11&quot; markerHeight=&quot;11&quot; orient=&quot;auto&quot;&gt;&lt;circle cx=&quot;5&quot; cy=&quot;5&quot; r=&quot;5&quot; class=&quot;arrowMarkerPath&quot; style=&quot;stroke-width:1;stroke-dasharray:1, 0&quot;&gt;&lt;/circle&gt;&lt;/marker&gt;&lt;marker id=&quot;mermaid-0_flowchart-v2-circleStart&quot; class=&quot;marker flowchart-v2&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;-1&quot; refY=&quot;5&quot; markerUnits=&quot;userSpaceOnUse&quot; markerWidth=&quot;11&quot; markerHeight=&quot;11&quot; orient=&quot;auto&quot;&gt;&lt;circle cx=&quot;5&quot; cy=&quot;5&quot; r=&quot;5&quot; class=&quot;arrowMarkerPath&quot; style=&quot;stroke-width:1;stroke-dasharray:1, 0&quot;&gt;&lt;/circle&gt;&lt;/marker&gt;&lt;marker id=&quot;mermaid-0_flowchart-v2-crossEnd&quot; class=&quot;marker cross flowchart-v2&quot; viewBox=&quot;0 0 11 11&quot; refX=&quot;12&quot; refY=&quot;5.2&quot; markerUnits=&quot;userSpaceOnUse&quot; markerWidth=&quot;11&quot; markerHeight=&quot;11&quot; orient=&quot;auto&quot;&gt;&lt;path d=&quot;M 1,1 l 9,9 M 10,1 l -9,9&quot; class=&quot;arrowMarkerPath&quot; style=&quot;stroke-width:2;stroke-dasharray:1, 0&quot;&gt;&lt;/path&gt;&lt;/marker&gt;&lt;marker id=&quot;mermaid-0_flowchart-v2-crossStart&quot; class=&quot;marker cross flowchart-v2&quot; viewBox=&quot;0 0 11 11&quot; refX=&quot;-1&quot; refY=&quot;5.2&quot; markerUnits=&quot;userSpaceOnUse&quot; markerWidth=&quot;11&quot; markerHeight=&quot;11&quot; orient=&quot;auto&quot;&gt;&lt;path d=&quot;M 1,1 l 9,9 M 10,1 l -9,9&quot; class=&quot;arrowMarkerPath&quot; style=&quot;stroke-width:2;stroke-dasharray:1, 0&quot;&gt;&lt;/path&gt;&lt;/marker&gt;&lt;g class=&quot;root&quot;&gt;&lt;g class=&quot;clusters&quot;&gt;&lt;g class=&quot;cluster&quot; id=&quot;Host&quot; data-look=&quot;classic&quot;&gt;&lt;rect style=&quot;&quot; x=&quot;8&quot; y=&quot;134.421875&quot; width=&quot;997.7421875&quot; height=&quot;690&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;cluster-label&quot; transform=&quot;translate(460.11328125, 134.421875)&quot;&gt;&lt;foreignObject width=&quot;93.515625&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;nodeLabel&quot;&gt;&lt;p&gt;Host System&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;cluster&quot; id=&quot;DOCKER&quot; data-look=&quot;classic&quot;&gt;&lt;rect style=&quot;&quot; x=&quot;28&quot; y=&quot;567.421875&quot; width=&quot;718.34375&quot; height=&quot;232&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;cluster-label&quot; transform=&quot;translate(355.6484375, 567.421875)&quot;&gt;&lt;foreignObject width=&quot;63.046875&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;nodeLabel&quot;&gt;&lt;p&gt;DOCKER&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgePaths&quot;&gt;&lt;path d=&quot;M826.574,84.422L826.574,88.589C826.574,92.755,826.574,101.089,826.574,109.422C826.574,117.755,826.574,126.089,826.574,133.755C826.574,141.422,826.574,148.422,826.574,151.922L826.574,155.422&quot; id=&quot;L_Internet_UFW_0&quot; class=&quot;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&quot; style=&quot;&quot; data-edge=&quot;true&quot; data-et=&quot;edge&quot; data-id=&quot;L_Internet_UFW_0&quot; data-points=&quot;W3sieCI6ODI2LjU3NDIxODc1LCJ5Ijo4NC40MjE4NzV9LHsieCI6ODI2LjU3NDIxODc1LCJ5IjoxMDkuNDIxODc1fSx7IngiOjgyNi41NzQyMTg3NSwieSI6MTM0LjQyMTg3NX0seyJ4Ijo4MjYuNTc0MjE4NzUsInkiOjE1OS40MjE4NzV9XQ==&quot; marker-end=&quot;url(#mermaid-0_flowchart-v2-pointEnd)&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M748.434,192.437L648.87,200.101C549.306,207.765,350.178,223.094,250.615,234.258C151.051,245.422,151.051,252.422,151.051,255.922L151.051,259.422&quot; id=&quot;L_UFW_PSAD_0&quot; class=&quot;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&quot; style=&quot;&quot; data-edge=&quot;true&quot; data-et=&quot;edge&quot; data-id=&quot;L_UFW_PSAD_0&quot; data-points=&quot;W3sieCI6NzQ4LjQzMzU5Mzc1LCJ5IjoxOTIuNDM2OTMyNzY3NzAzM30seyJ4IjoxNTEuMDUwNzgxMjUsInkiOjIzOC40MjE4NzV9LHsieCI6MTUxLjA1MDc4MTI1LCJ5IjoyNjMuNDIxODc1fV0=&quot; marker-end=&quot;url(#mermaid-0_flowchart-v2-pointEnd)&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M889.235,213.422L898.905,217.589C908.575,221.755,927.914,230.089,937.584,244.922C947.254,259.755,947.254,281.089,947.254,308.422C947.254,335.755,947.254,369.089,947.254,400.422C947.254,431.755,947.254,461.089,947.254,484.422C947.254,507.755,947.254,525.089,947.254,537.922C947.254,550.755,947.254,559.089,947.254,571.922C947.254,584.755,947.254,602.089,947.254,621.422C947.254,640.755,947.254,662.089,943.829,678.353C940.404,694.618,933.554,705.814,930.129,711.412L926.704,717.01&quot; id=&quot;L_UFW_F2B_0&quot; class=&quot;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&quot; style=&quot;&quot; data-edge=&quot;true&quot; data-et=&quot;edge&quot; data-id=&quot;L_UFW_F2B_0&quot; data-points=&quot;W3sieCI6ODg5LjIzNDgyNTcyMTE1MzgsInkiOjIxMy40MjE4NzV9LHsieCI6OTQ3LjI1MzkwNjI1LCJ5IjoyMzguNDIxODc1fSx7IngiOjk0Ny4yNTM5MDYyNSwieSI6MzAyLjQyMTg3NX0seyJ4Ijo5NDcuMjUzOTA2MjUsInkiOjQwMi40MjE4NzV9LHsieCI6OTQ3LjI1MzkwNjI1LCJ5Ijo0OTAuNDIxODc1fSx7IngiOjk0Ny4yNTM5MDYyNSwieSI6NTQyLjQyMTg3NX0seyJ4Ijo5NDcuMjUzOTA2MjUsInkiOjU2Ny40MjE4NzV9LHsieCI6OTQ3LjI1MzkwNjI1LCJ5Ijo2MTkuNDIxODc1fSx7IngiOjk0Ny4yNTM5MDYyNSwieSI6NjgzLjQyMTg3NX0seyJ4Ijo5MjQuNjE2Njk5MjE4NzUsInkiOjcyMC40MjE4NzV9XQ==&quot; marker-end=&quot;url(#mermaid-0_flowchart-v2-pointEnd)&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M826.574,213.422L826.574,217.589C826.574,221.755,826.574,230.089,826.574,244.922C826.574,259.755,826.574,281.089,826.574,308.422C826.574,335.755,826.574,369.089,800.656,395.683C774.739,422.278,722.903,442.135,696.985,452.063L671.067,461.991&quot; id=&quot;L_UFW_IPTABLES_0&quot; class=&quot;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&quot; style=&quot;&quot; data-edge=&quot;true&quot; data-et=&quot;edge&quot; data-id=&quot;L_UFW_IPTABLES_0&quot; data-points=&quot;W3sieCI6ODI2LjU3NDIxODc1LCJ5IjoyMTMuNDIxODc1fSx7IngiOjgyNi41NzQyMTg3NSwieSI6MjM4LjQyMTg3NX0seyJ4Ijo4MjYuNTc0MjE4NzUsInkiOjMwMi40MjE4NzV9LHsieCI6ODI2LjU3NDIxODc1LCJ5Ijo0MDIuNDIxODc1fSx7IngiOjY2Ny4zMzE5NDI0NzE1OTA5LCJ5Ijo0NjMuNDIxODc1fV0=&quot; marker-end=&quot;url(#mermaid-0_flowchart-v2-pointEnd)&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M151.051,341.422L151.051,351.589C151.051,361.755,151.051,382.089,205.826,403.068C260.602,424.047,370.153,445.673,424.929,456.485L479.705,467.298&quot; id=&quot;L_PSAD_IPTABLES_0&quot; class=&quot;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&quot; style=&quot;&quot; data-edge=&quot;true&quot; data-et=&quot;edge&quot; data-id=&quot;L_PSAD_IPTABLES_0&quot; data-points=&quot;W3sieCI6MTUxLjA1MDc4MTI1LCJ5IjozNDEuNDIxODc1fSx7IngiOjE1MS4wNTA3ODEyNSwieSI6NDAyLjQyMTg3NX0seyJ4Ijo0ODMuNjI4OTA2MjUsInkiOjQ2OC4wNzI1NzA3MzQ0NjQyNX1d&quot; marker-end=&quot;url(#mermaid-0_flowchart-v2-pointEnd)&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M876.833,720.422L869.692,714.255C862.551,708.089,848.27,695.755,841.129,678.922C833.988,662.089,833.988,640.755,833.988,621.422C833.988,602.089,833.988,584.755,833.988,571.922C833.988,559.089,833.988,550.755,813.986,542.202C793.983,533.65,753.978,524.877,733.976,520.491L713.974,516.105&quot; id=&quot;L_F2B_IPTABLES_0&quot; class=&quot;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&quot; style=&quot;&quot; data-edge=&quot;true&quot; data-et=&quot;edge&quot; data-id=&quot;L_F2B_IPTABLES_0&quot; data-points=&quot;W3sieCI6ODc2LjgzMjc2MzY3MTg3NSwieSI6NzIwLjQyMTg3NX0seyJ4Ijo4MzMuOTg4MjgxMjUsInkiOjY4My40MjE4NzV9LHsieCI6ODMzLjk4ODI4MTI1LCJ5Ijo2MTkuNDIxODc1fSx7IngiOjgzMy45ODgyODEyNSwieSI6NTY3LjQyMTg3NX0seyJ4Ijo4MzMuOTg4MjgxMjUsInkiOjU0Mi40MjE4NzV9LHsieCI6NzEwLjA2NjQwNjI1LCJ5Ijo1MTUuMjQ4Mzg4ODAzNzgyMX1d&quot; marker-end=&quot;url(#mermaid-0_flowchart-v2-pointEnd)&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M413.344,634.258L370.076,642.452C326.807,650.646,240.271,667.034,197.003,680.728C153.734,694.422,153.734,705.422,153.734,710.922L153.734,716.422&quot; id=&quot;L_TRAEFIK_APP1_0&quot; class=&quot;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&quot; style=&quot;&quot; data-edge=&quot;true&quot; data-et=&quot;edge&quot; data-id=&quot;L_TRAEFIK_APP1_0&quot; data-points=&quot;W3sieCI6NDEzLjM0Mzc1LCJ5Ijo2MzQuMjU4MjUyMDg2MzE5M30seyJ4IjoxNTMuNzM0Mzc1LCJ5Ijo2ODMuNDIxODc1fSx7IngiOjE1My43MzQzNzUsInkiOjcyMC40MjE4NzV9XQ==&quot; marker-end=&quot;url(#mermaid-0_flowchart-v2-pointEnd)&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M446.764,646.422L436.504,652.589C426.244,658.755,405.724,671.089,395.463,682.755C385.203,694.422,385.203,705.422,385.203,710.922L385.203,716.422&quot; id=&quot;L_TRAEFIK_APP2_0&quot; class=&quot;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&quot; style=&quot;&quot; data-edge=&quot;true&quot; data-et=&quot;edge&quot; data-id=&quot;L_TRAEFIK_APP2_0&quot; data-points=&quot;W3sieCI6NDQ2Ljc2NDQwNDI5Njg3NSwieSI6NjQ2LjQyMTg3NX0seyJ4IjozODUuMjAzMTI1LCJ5Ijo2ODMuNDIxODc1fSx7IngiOjM4NS4yMDMxMjUsInkiOjcyMC40MjE4NzV9XQ==&quot; marker-end=&quot;url(#mermaid-0_flowchart-v2-pointEnd)&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M544.415,646.422L556.458,652.589C568.501,658.755,592.586,671.089,604.629,682.755C616.672,694.422,616.672,705.422,616.672,710.922L616.672,716.422&quot; id=&quot;L_TRAEFIK_APP3_0&quot; class=&quot;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&quot; style=&quot;&quot; data-edge=&quot;true&quot; data-et=&quot;edge&quot; data-id=&quot;L_TRAEFIK_APP3_0&quot; data-points=&quot;W3sieCI6NTQ0LjQxNTI4MzIwMzEyNSwieSI6NjQ2LjQyMTg3NX0seyJ4Ijo2MTYuNjcxODc1LCJ5Ijo2ODMuNDIxODc1fSx7IngiOjYxNi42NzE4NzUsInkiOjcyMC40MjE4NzV9XQ==&quot; marker-end=&quot;url(#mermaid-0_flowchart-v2-pointEnd)&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M570.031,645.836L588.611,652.101C607.19,658.365,644.349,670.893,689.722,684.726C735.096,698.558,788.684,713.694,815.478,721.261L842.272,728.829&quot; id=&quot;L_TRAEFIK_F2B_0&quot; class=&quot;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&quot; style=&quot;&quot; data-edge=&quot;true&quot; data-et=&quot;edge&quot; data-id=&quot;L_TRAEFIK_F2B_0&quot; data-points=&quot;W3sieCI6NTcwLjAzMTI1LCJ5Ijo2NDUuODM2MzI5NDU5Mzk4M30seyJ4Ijo2ODEuNTA3ODEyNSwieSI6NjgzLjQyMTg3NX0seyJ4Ijo4NDYuMTIxMDkzNzUsInkiOjcyOS45MTY2NzczNTE0NDAzfV0=&quot; marker-end=&quot;url(#mermaid-0_flowchart-v2-pointEnd)&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M542.245,517.422L533.819,521.589C525.393,525.755,508.54,534.089,500.114,541.755C491.688,549.422,491.688,556.422,491.688,559.922L491.688,563.422&quot; id=&quot;L_IPTABLES_DOCKER_0&quot; class=&quot;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&quot; style=&quot;&quot; data-edge=&quot;true&quot; data-et=&quot;edge&quot; data-id=&quot;L_IPTABLES_DOCKER_0&quot; data-points=&quot;W3sieCI6NTQyLjI0NTI2NzQyNzg4NDYsInkiOjUxNy40MjE4NzV9LHsieCI6NDkxLjY4NzUsInkiOjU0Mi40MjE4NzV9LHsieCI6NDkxLjY4NzUsInkiOjU2Ny40MjE4NzV9LHsieCI6NDkxLjY4NzUsInkiOjU5Mi40MjE4NzV9XQ==&quot; marker-end=&quot;url(#mermaid-0_flowchart-v2-pointEnd)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabels&quot;&gt;&lt;g class=&quot;edgeLabel&quot;&gt;&lt;g class=&quot;label&quot; data-id=&quot;L_Internet_UFW_0&quot; transform=&quot;translate(0, 0)&quot;&gt;&lt;foreignObject width=&quot;0&quot; height=&quot;0&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; class=&quot;labelBkg&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;edgeLabel&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot;&gt;&lt;g class=&quot;label&quot; data-id=&quot;L_UFW_PSAD_0&quot; transform=&quot;translate(0, 0)&quot;&gt;&lt;foreignObject width=&quot;0&quot; height=&quot;0&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; class=&quot;labelBkg&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;edgeLabel&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot;&gt;&lt;g class=&quot;label&quot; data-id=&quot;L_UFW_F2B_0&quot; transform=&quot;translate(0, 0)&quot;&gt;&lt;foreignObject width=&quot;0&quot; height=&quot;0&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; class=&quot;labelBkg&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;edgeLabel&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot;&gt;&lt;g class=&quot;label&quot; data-id=&quot;L_UFW_IPTABLES_0&quot; transform=&quot;translate(0, 0)&quot;&gt;&lt;foreignObject width=&quot;0&quot; height=&quot;0&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; class=&quot;labelBkg&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;edgeLabel&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot; transform=&quot;translate(151.05078125, 402.421875)&quot;&gt;&lt;g class=&quot;label&quot; data-id=&quot;L_PSAD_IPTABLES_0&quot; transform=&quot;translate(-39.6796875, -36)&quot;&gt;&lt;foreignObject width=&quot;79.359375&quot; height=&quot;72&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; class=&quot;labelBkg&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;edgeLabel&quot;&gt;&lt;p&gt;Detects&lt;br&gt;&lt;/br&gt;Suspicious&lt;br&gt;&lt;/br&gt;Traffic&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot; transform=&quot;translate(833.98828125, 619.421875)&quot;&gt;&lt;g class=&quot;label&quot; data-id=&quot;L_F2B_IPTABLES_0&quot; transform=&quot;translate(-58.3125, -24)&quot;&gt;&lt;foreignObject width=&quot;116.625&quot; height=&quot;48&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; class=&quot;labelBkg&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;edgeLabel&quot;&gt;&lt;p&gt;Bans IPs Based&lt;br&gt;&lt;/br&gt;on Log Analysis&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot;&gt;&lt;g class=&quot;label&quot; data-id=&quot;L_TRAEFIK_APP1_0&quot; transform=&quot;translate(0, 0)&quot;&gt;&lt;foreignObject width=&quot;0&quot; height=&quot;0&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; class=&quot;labelBkg&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;edgeLabel&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot;&gt;&lt;g class=&quot;label&quot; data-id=&quot;L_TRAEFIK_APP2_0&quot; transform=&quot;translate(0, 0)&quot;&gt;&lt;foreignObject width=&quot;0&quot; height=&quot;0&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; class=&quot;labelBkg&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;edgeLabel&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot;&gt;&lt;g class=&quot;label&quot; data-id=&quot;L_TRAEFIK_APP3_0&quot; transform=&quot;translate(0, 0)&quot;&gt;&lt;foreignObject width=&quot;0&quot; height=&quot;0&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; class=&quot;labelBkg&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;edgeLabel&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot; transform=&quot;translate(707.20796, 690.68085)&quot;&gt;&lt;g class=&quot;label&quot; data-id=&quot;L_TRAEFIK_F2B_0&quot; transform=&quot;translate(-44.8359375, -12)&quot;&gt;&lt;foreignObject width=&quot;89.671875&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; class=&quot;labelBkg&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;edgeLabel&quot;&gt;&lt;p&gt;Access Logs&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot;&gt;&lt;g class=&quot;label&quot; data-id=&quot;L_IPTABLES_DOCKER_0&quot; transform=&quot;translate(0, 0)&quot;&gt;&lt;foreignObject width=&quot;0&quot; height=&quot;0&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; class=&quot;labelBkg&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;edgeLabel&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;nodes&quot;&gt;&lt;g class=&quot;node default&quot; id=&quot;flowchart-Internet-0&quot; transform=&quot;translate(826.57421875, 46.2109375)&quot;&gt;&lt;circle class=&quot;basic label-container&quot; style=&quot;&quot; r=&quot;38.2109375&quot; cx=&quot;0&quot; cy=&quot;0&quot;&gt;&lt;/circle&gt;&lt;g class=&quot;label&quot; style=&quot;&quot; transform=&quot;translate(-30.7109375, -12)&quot;&gt;&lt;rect&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;61.421875&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;nodeLabel&quot;&gt;&lt;p&gt;Internet&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;node default firewall&quot; id=&quot;flowchart-UFW-1&quot; transform=&quot;translate(826.57421875, 186.421875)&quot;&gt;&lt;rect class=&quot;basic label-container&quot; style=&quot;fill:#2563eb33 !important;stroke:#2563eb !important;stroke-width:1.5px !important&quot; x=&quot;-78.140625&quot; y=&quot;-27&quot; width=&quot;156.28125&quot; height=&quot;54&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; style=&quot;&quot; transform=&quot;translate(-48.140625, -12)&quot;&gt;&lt;rect&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;96.28125&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;nodeLabel&quot;&gt;&lt;p&gt;UFW Firewall&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;node default monitoring&quot; id=&quot;flowchart-PSAD-3&quot; transform=&quot;translate(151.05078125, 302.421875)&quot;&gt;&lt;rect class=&quot;basic label-container&quot; style=&quot;fill:#8b5cf633 !important;stroke:#8b5cf6 !important;stroke-width:1.5px !important&quot; x=&quot;-102.8828125&quot; y=&quot;-39&quot; width=&quot;205.765625&quot; height=&quot;78&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; style=&quot;&quot; transform=&quot;translate(-72.8828125, -24)&quot;&gt;&lt;rect&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;145.765625&quot; height=&quot;48&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;nodeLabel&quot;&gt;&lt;p&gt;PSAD&lt;br&gt;&lt;/br&gt;Intrusion Detection&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;node default monitoring&quot; id=&quot;flowchart-F2B-5&quot; transform=&quot;translate(908.09765625, 747.421875)&quot;&gt;&lt;rect class=&quot;basic label-container&quot; style=&quot;fill:#8b5cf633 !important;stroke:#8b5cf6 !important;stroke-width:1.5px !important&quot; x=&quot;-61.9765625&quot; y=&quot;-27&quot; width=&quot;123.953125&quot; height=&quot;54&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; style=&quot;&quot; transform=&quot;translate(-31.9765625, -12)&quot;&gt;&lt;rect&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;63.953125&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;nodeLabel&quot;&gt;&lt;p&gt;Fail2Ban&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;node default firewall&quot; id=&quot;flowchart-IPTABLES-7&quot; transform=&quot;translate(596.84765625, 490.421875)&quot;&gt;&lt;rect class=&quot;basic label-container&quot; style=&quot;fill:#2563eb33 !important;stroke:#2563eb !important;stroke-width:1.5px !important&quot; x=&quot;-113.21875&quot; y=&quot;-27&quot; width=&quot;226.4375&quot; height=&quot;54&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; style=&quot;&quot; transform=&quot;translate(-83.21875, -12)&quot;&gt;&lt;rect&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;166.4375&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;nodeLabel&quot;&gt;&lt;p&gt;Custom iptables Rules&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;node default container&quot; id=&quot;flowchart-TRAEFIK-14&quot; transform=&quot;translate(491.6875, 619.421875)&quot;&gt;&lt;rect class=&quot;basic label-container&quot; style=&quot;fill:#10b98133 !important;stroke:#10b981 !important;stroke-width:1.5px !important&quot; x=&quot;-78.34375&quot; y=&quot;-27&quot; width=&quot;156.6875&quot; height=&quot;54&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; style=&quot;&quot; transform=&quot;translate(-48.34375, -12)&quot;&gt;&lt;rect&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;96.6875&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;nodeLabel&quot;&gt;&lt;p&gt;Traefik Proxy&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;node default container&quot; id=&quot;flowchart-APP1-15&quot; transform=&quot;translate(153.734375, 747.421875)&quot;&gt;&lt;rect class=&quot;basic label-container&quot; style=&quot;fill:#10b98133 !important;stroke:#10b981 !important;stroke-width:1.5px !important&quot; x=&quot;-90.734375&quot; y=&quot;-27&quot; width=&quot;181.46875&quot; height=&quot;54&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; style=&quot;&quot; transform=&quot;translate(-60.734375, -12)&quot;&gt;&lt;rect&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;121.46875&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;nodeLabel&quot;&gt;&lt;p&gt;App Container 1&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;node default container&quot; id=&quot;flowchart-APP2-17&quot; transform=&quot;translate(385.203125, 747.421875)&quot;&gt;&lt;rect class=&quot;basic label-container&quot; style=&quot;fill:#10b98133 !important;stroke:#10b981 !important;stroke-width:1.5px !important&quot; x=&quot;-90.734375&quot; y=&quot;-27&quot; width=&quot;181.46875&quot; height=&quot;54&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; style=&quot;&quot; transform=&quot;translate(-60.734375, -12)&quot;&gt;&lt;rect&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;121.46875&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;nodeLabel&quot;&gt;&lt;p&gt;App Container 2&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;node default container&quot; id=&quot;flowchart-APP3-19&quot; transform=&quot;translate(616.671875, 747.421875)&quot;&gt;&lt;rect class=&quot;basic label-container&quot; style=&quot;fill:#10b98133 !important;stroke:#10b981 !important;stroke-width:1.5px !important&quot; x=&quot;-90.734375&quot; y=&quot;-27&quot; width=&quot;181.46875&quot; height=&quot;54&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; style=&quot;&quot; transform=&quot;translate(-60.734375, -12)&quot;&gt;&lt;rect&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;121.46875&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;nodeLabel&quot;&gt;&lt;p&gt;App Container 3&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;
&lt;p&gt;Think of these tools as concentric security rings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UFW defines what doors are open to the internet&lt;/li&gt;
&lt;li&gt;PSAD monitors suspicious activity at those doors&lt;/li&gt;
&lt;li&gt;Fail2Ban watches how visitors behave once they&apos;re allowed through a door&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;layer-1-ufw-uncomplicated-firewall&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#layer-1-ufw-uncomplicated-firewall&quot;&gt;Layer 1: UFW (Uncomplicated Firewall)&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;UFW provides a simplified interface to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;iptables&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. My approach is &lt;strong&gt;&quot;deny by default&quot;&lt;/strong&gt; - block everything unless explicitly allowed.&lt;/p&gt;
&lt;h2 id=&quot;installation&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#installation&quot;&gt;Installation&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; apt install ufw&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;configuration&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#configuration&quot;&gt;Configuration&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Deny all traffic by default&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; ufw default deny outgoing comment &apos;deny all outgoing traffic&apos;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; ufw default deny incoming comment &apos;deny all incoming traffic&apos;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Allow SSH (don&apos;t lock yourself out!)&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; ufw limit in ssh comment &apos;allow SSH connections in&apos;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Allow web traffic for Traefik&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; ufw allow 80/tcp comment &apos;allow HTTP&apos;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; ufw allow 443/tcp comment &apos;allow HTTPS&apos;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Allow essential outbound traffic&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; ufw allow out 53 comment &apos;allow DNS calls out&apos;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; ufw allow out 123 comment &apos;allow NTP out&apos;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; ufw allow out http comment &apos;allow HTTP traffic out&apos;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; ufw allow out https comment &apos;allow HTTPS traffic out&apos;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;enable-and-verify&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#enable-and-verify&quot;&gt;Enable and Verify&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; ufw enable
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; ufw status verbose&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;layer-2-psad-port-scan-attack-detector&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#layer-2-psad-port-scan-attack-detector&quot;&gt;Layer 2: PSAD (Port Scan Attack Detector)&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;PSAD monitors network traffic through iptables logs to detect and optionally block scanning activity and other suspicious traffic.&lt;/p&gt;
&lt;h2 id=&quot;installation-1&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#installation-1&quot;&gt;Installation&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; apt install psad&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;configuration-1&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#configuration-1&quot;&gt;Configuration&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Make a backup of the configuration:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; cp --archive /etc/psad/psad.conf /etc/psad/psad.conf-BACKUP&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Edit &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/psad/psad.conf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and update these settings:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;EMAIL_ADDRESSES         your@email.address;&lt;/span&gt;
&lt;span&gt;HOSTNAME                your-server-hostname;&lt;/span&gt;
&lt;span&gt;EXPECT_TCP_OPTIONS      Y;         # Enable TCP options logging&lt;/span&gt;
&lt;span&gt;ENABLE_PSADWATCHD       Y;&lt;/span&gt;
&lt;span&gt;ENABLE_AUTO_IDS         Y;         # Enable auto-blocking&lt;/span&gt;
&lt;span&gt;ENABLE_AUTO_IDS_EMAILS  Y;         # Enable email notifications&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure UFW to log traffic for PSAD by modifying both &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/ufw/before.rules&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; (for IPv4) and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/ufw/before6.rules&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; (for IPv6). First make a backup of both files:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; cp --archive /etc/ufw/before.rules /etc/ufw/before.rules-BACKUP
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; cp --archive /etc/ufw/before6.rules /etc/ufw/before6.rules-BACKUP&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Add these lines to both files before the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;COMMIT&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; line:&lt;/p&gt;
&lt;p&gt;In &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/ufw/before.rules&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;# log all traffic so psad can analyze&lt;/span&gt;
 
&lt;span&gt;-A ufw-before-input -j LOG --log-tcp-options --log-prefix &quot;[IPTABLES] &quot;&lt;/span&gt;
&lt;span&gt;-A ufw-before-forward -j LOG --log-tcp-options --log-prefix &quot;[IPTABLES] &quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;In &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/ufw/before6.rules&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;# log all traffic so psad can analyze&lt;/span&gt;
 
&lt;span&gt;-A ufw6-before-input -j LOG --log-tcp-options --log-prefix &quot;[IPTABLES] &quot;&lt;/span&gt;
&lt;span&gt;-A ufw6-before-forward -j LOG --log-tcp-options --log-prefix &quot;[IPTABLES] &quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Using &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;ufw-before-input&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;ufw-before-forward&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; chains instead of directly modifying &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;INPUT&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;FORWARD&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is crucial for proper integration with UFW.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reload and Verify&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; ufw reload
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; psad -R
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; psad --sig-update
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; psad -H&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Analyze Firewall Logs and Check PSAD Status&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; psad --fw-analyze
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; psad --Status&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;If &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;psad --fw-analyze&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; shows issues, you can check your mail by executing the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;mail&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; command. For this to work, you need to provide &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;&amp;#x3C;user&gt;@localhost&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; as the email address in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;EMAIL_ADDRESSES&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; field of the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;psad.conf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;layer-3-fail2ban-application-intrusion-prevention&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#layer-3-fail2ban-application-intrusion-prevention&quot;&gt;Layer 3: Fail2Ban (Application Intrusion Prevention)&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Fail2Ban scans log files for malicious activity and blocks offending IPs using iptables. We will configure it to monitor Traefik logs for suspicious behavior.&lt;/p&gt;
&lt;h2 id=&quot;installation-2&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#installation-2&quot;&gt;Installation&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; apt install fail2ban&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;basic-configuration&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#basic-configuration&quot;&gt;Basic Configuration&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Create a local configuration file to avoid editing the default one:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; vim /etc/fail2ban/jail.local&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Add the following content:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;ini&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;ini&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;[DEFAULT]&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Ignore local IPs&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;ignoreip&lt;/span&gt; = 127.0.0.1/8 192.168.0.0/16 10.0.0.0/8 172.16.0.0/12
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Email notifications&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;destemail&lt;/span&gt; = your@email.address
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;sender&lt;/span&gt; = your@email.address
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;mta&lt;/span&gt; = mail
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Get detailed email alerts&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;action&lt;/span&gt; = %(action_mwl)s&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;traefik-configuration&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#traefik-configuration&quot;&gt;Traefik Configuration&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First, make sure Traefik is configured to output access logs in a format Fail2Ban can process:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# In traefik.yml&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;log&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  level&lt;/span&gt;: debug
 
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;accessLog&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  filepath&lt;/span&gt;: /var/log/traefik/access.log
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  format&lt;/span&gt;: common&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# In docker-compose.yml&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;services&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  traefik&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    image&lt;/span&gt;: traefik:v3
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    container_name&lt;/span&gt;: traefik
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    volumes&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;./traefik.yml:/etc/traefik/traefik.yml:ro
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;./logs:/var/log/traefik
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;      ...&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;      ...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;creating-traefik-filters-for-fail2ban&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#creating-traefik-filters-for-fail2ban&quot;&gt;Creating Traefik Filters for Fail2Ban&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Create a filter for authentication failures:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; vim /etc/fail2ban/filter.d/traefik-auth.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Add this content:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;ini&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;ini&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;[Definition]&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;failregex&lt;/span&gt; = ^&amp;#x3C;HOST&gt; - .* &quot;GET .* (401|403) .*$
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;            ^&amp;#x3C;HOST&gt; - .* &quot;&lt;/span&gt;POST .* (401|403) .*$
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;ignoreregex&lt;/span&gt; =&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Create a filter for rate limiting (this will require setting up Traefik&apos;s rate limiting middleware):&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; vim /etc/fail2ban/filter.d/traefik-ratelimit.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Add this content:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;ini&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;ini&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;[Definition]&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;failregex&lt;/span&gt; = ^&amp;#x3C;HOST&gt; - .* &quot;GET .* (429) .*$
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;            ^&amp;#x3C;HOST&gt; - .* &quot;&lt;/span&gt;POST .* (429) .*$
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;            ^&amp;#x3C;HOST&gt; - .* &lt;/span&gt;&quot;PUT .* (429) .*$
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;            ^&amp;#x3C;HOST&gt; - .* &quot;&lt;/span&gt;DELETE .* (429) .*$
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;ignoreregex&lt;/span&gt; =&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;setting-up-jail-configurations&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#setting-up-jail-configurations&quot;&gt;Setting Up Jail Configurations&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Create a jail file for Traefik:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; vim /etc/fail2ban/jail.d/traefik.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Add this content:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;ini&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;ini&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;[traefik-auth]&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;enabled&lt;/span&gt; = true
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;port&lt;/span&gt; = http,https
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;filter&lt;/span&gt; = traefik-auth
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;logpath&lt;/span&gt; = /path/to/your/traefik/logs/access.log
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;maxretry&lt;/span&gt; = 3
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;bantime&lt;/span&gt; = 1h
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;findtime&lt;/span&gt; = 10m
 
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;[traefik-ratelimit]&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;enabled&lt;/span&gt; = true
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;port&lt;/span&gt; = http,https
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;filter&lt;/span&gt; = traefik-ratelimit
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;logpath&lt;/span&gt; = /path/to/your/traefik/logs/access.log
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;maxretry&lt;/span&gt; = 5
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;bantime&lt;/span&gt; = 30m
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;findtime&lt;/span&gt; = 5m&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;integrating-docker-networking-with-security-tools&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#integrating-docker-networking-with-security-tools&quot;&gt;Integrating Docker Networking with Security Tools&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Docker&apos;s networking requires special attention to ensure our security tools work properly.&lt;/p&gt;
&lt;h2 id=&quot;the-challenge-with-docker-networks&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-challenge-with-docker-networks&quot;&gt;The Challenge with Docker Networks&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When you use Docker, it creates its own network namespace and manipulates iptables rules to handle routing between containers and the outside world. This presents two main challenges for Fail2Ban:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Visibility Issue:&lt;/strong&gt; In a standard Docker setup, container logs show the internal Docker network IPs (like 172.17.0.x) rather than the actual client IPs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ban Enforcement Issue:&lt;/strong&gt; When Fail2Ban tries to ban an IP, it adds rules to the host&apos;s iptables, but these rules might not affect traffic that&apos;s already being handled by Docker&apos;s networking rules.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;creating-a-custom-fail2ban-action-for-docker&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#creating-a-custom-fail2ban-action-for-docker&quot;&gt;Creating a Custom Fail2Ban Action for Docker&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; vim /etc/fail2ban/action.d/iptables-traefik-docker.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Add this content:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;ini&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;ini&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;[Definition]&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;actionstart&lt;/span&gt; = iptables -N f2b-traefik
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;              iptables -A f2b-traefik -j RETURN&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;              iptables -I FORWARD -p tcp -m multiport --dports 80,443 -j f2b-traefik&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;actionstop&lt;/span&gt; = iptables -D FORWARD -p tcp -m multiport --dports 80,443 -j f2b-traefik
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;             iptables -F f2b-traefik&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;             iptables -X f2b-traefik&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;actionban&lt;/span&gt; = iptables -I f2b-traefik 1 -s &amp;#x3C;ip&gt; -j DROP
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;actionunban&lt;/span&gt; = iptables -D f2b-traefik -s &amp;#x3C;ip&gt; -j DROP&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Update your jail configuration to use this action:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;ini&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;ini&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;[traefik-auth]&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# ... existing configuration&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;action&lt;/span&gt; = iptables-traefik-docker
 
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;[traefik-ratelimit]&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# ... existing configuration&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;action&lt;/span&gt; = iptables-traefik-docker&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;how-the-solution-works&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#how-the-solution-works&quot;&gt;How the Solution Works&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Getting Real Client IPs in Traefik
First, we need to ensure Traefik logs show the real client IPs:
&lt;ul&gt;
&lt;li&gt;Traefik automatically captures the real client IP when properly configured&lt;/li&gt;
&lt;li&gt;The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;accesslog.format=common&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; setting ensures these IPs are logged in a format Fail2Ban can parse&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The Custom iptables Action (&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;iptables-traefik-docker.conf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;) modifies iptables to work with Docker&apos;s networking:
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;On Start (actionstart):&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;iptables -N f2b-traefik&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;: Creates a new custom chain called &quot;f2b-traefik&quot;&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;iptables -A f2b-traefik -j RETURN&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;: Adds a default rule that returns traffic flow to the parent chain&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;iptables -I FORWARD -p tcp -m multiport --dports 80,443 -j f2b-traefik&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;: Inserts a rule at the beginning of the FORWARD chain to route HTTP/HTTPS traffic through our custom chain&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This setup intercepts packets in the FORWARD chain, which is crucial because Docker traffic typically passes through this chain.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;On Ban (actionban):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;iptables -I f2b-traefik 1 -s &amp;#x3C;ip&gt; -j DROP&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;: Inserts a rule at the beginning of our custom chain to drop packets from the banned IP&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;On Unban (actionunban):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;iptables -D f2b-traefik -s &amp;#x3C;ip&gt; -j DROP&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;: Removes the ban rule for the specific IP&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;On Stop (actionstop):&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;iptables -D FORWARD -p tcp -m multiport --dports 80,443 -j f2b-traefik&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;: Removes our custom chain from the FORWARD chain&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;iptables -F f2b-traefik&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;: Flushes (clears) all rules in our custom chain&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;iptables -X f2b-traefik&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;: Deletes our custom chain&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;svg id=&quot;mermaid-1&quot; width=&quot;100%&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; viewBox=&quot;0 0 512.7734375 582&quot; role=&quot;graphics-document document&quot; aria-roledescription=&quot;flowchart-v2&quot;&gt;&lt;g&gt;&lt;marker id=&quot;mermaid-1_flowchart-v2-pointEnd&quot; class=&quot;marker flowchart-v2&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;5&quot; refY=&quot;5&quot; markerUnits=&quot;userSpaceOnUse&quot; markerWidth=&quot;8&quot; markerHeight=&quot;8&quot; orient=&quot;auto&quot;&gt;&lt;path d=&quot;M 0 0 L 10 5 L 0 10 z&quot; class=&quot;arrowMarkerPath&quot; style=&quot;stroke-width:1;stroke-dasharray:1, 0&quot;&gt;&lt;/path&gt;&lt;/marker&gt;&lt;marker id=&quot;mermaid-1_flowchart-v2-pointStart&quot; class=&quot;marker flowchart-v2&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;4.5&quot; refY=&quot;5&quot; markerUnits=&quot;userSpaceOnUse&quot; markerWidth=&quot;8&quot; markerHeight=&quot;8&quot; orient=&quot;auto&quot;&gt;&lt;path d=&quot;M 0 5 L 10 10 L 10 0 z&quot; class=&quot;arrowMarkerPath&quot; style=&quot;stroke-width:1;stroke-dasharray:1, 0&quot;&gt;&lt;/path&gt;&lt;/marker&gt;&lt;marker id=&quot;mermaid-1_flowchart-v2-circleEnd&quot; class=&quot;marker flowchart-v2&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;11&quot; refY=&quot;5&quot; markerUnits=&quot;userSpaceOnUse&quot; markerWidth=&quot;11&quot; markerHeight=&quot;11&quot; orient=&quot;auto&quot;&gt;&lt;circle cx=&quot;5&quot; cy=&quot;5&quot; r=&quot;5&quot; class=&quot;arrowMarkerPath&quot; style=&quot;stroke-width:1;stroke-dasharray:1, 0&quot;&gt;&lt;/circle&gt;&lt;/marker&gt;&lt;marker id=&quot;mermaid-1_flowchart-v2-circleStart&quot; class=&quot;marker flowchart-v2&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;-1&quot; refY=&quot;5&quot; markerUnits=&quot;userSpaceOnUse&quot; markerWidth=&quot;11&quot; markerHeight=&quot;11&quot; orient=&quot;auto&quot;&gt;&lt;circle cx=&quot;5&quot; cy=&quot;5&quot; r=&quot;5&quot; class=&quot;arrowMarkerPath&quot; style=&quot;stroke-width:1;stroke-dasharray:1, 0&quot;&gt;&lt;/circle&gt;&lt;/marker&gt;&lt;marker id=&quot;mermaid-1_flowchart-v2-crossEnd&quot; class=&quot;marker cross flowchart-v2&quot; viewBox=&quot;0 0 11 11&quot; refX=&quot;12&quot; refY=&quot;5.2&quot; markerUnits=&quot;userSpaceOnUse&quot; markerWidth=&quot;11&quot; markerHeight=&quot;11&quot; orient=&quot;auto&quot;&gt;&lt;path d=&quot;M 1,1 l 9,9 M 10,1 l -9,9&quot; class=&quot;arrowMarkerPath&quot; style=&quot;stroke-width:2;stroke-dasharray:1, 0&quot;&gt;&lt;/path&gt;&lt;/marker&gt;&lt;marker id=&quot;mermaid-1_flowchart-v2-crossStart&quot; class=&quot;marker cross flowchart-v2&quot; viewBox=&quot;0 0 11 11&quot; refX=&quot;-1&quot; refY=&quot;5.2&quot; markerUnits=&quot;userSpaceOnUse&quot; markerWidth=&quot;11&quot; markerHeight=&quot;11&quot; orient=&quot;auto&quot;&gt;&lt;path d=&quot;M 1,1 l 9,9 M 10,1 l -9,9&quot; class=&quot;arrowMarkerPath&quot; style=&quot;stroke-width:2;stroke-dasharray:1, 0&quot;&gt;&lt;/path&gt;&lt;/marker&gt;&lt;g class=&quot;root&quot;&gt;&lt;g class=&quot;clusters&quot;&gt;&lt;/g&gt;&lt;g class=&quot;edgePaths&quot;&gt;&lt;path d=&quot;M277.711,62L277.711,68.167C277.711,74.333,277.711,86.667,277.711,98.333C277.711,110,277.711,121,277.711,126.5L277.711,132&quot; id=&quot;L_client_iptables_0&quot; class=&quot;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&quot; style=&quot;&quot; data-edge=&quot;true&quot; data-et=&quot;edge&quot; data-id=&quot;L_client_iptables_0&quot; data-points=&quot;W3sieCI6Mjc3LjcxMDkzNzUsInkiOjYyfSx7IngiOjI3Ny43MTA5Mzc1LCJ5Ijo5OX0seyJ4IjoyNzcuNzEwOTM3NSwieSI6MTM2fV0=&quot; marker-end=&quot;url(#mermaid-1_flowchart-v2-pointEnd)&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M250.233,190L243.957,196.167C237.681,202.333,225.13,214.667,218.854,226.333C212.578,238,212.578,249,212.578,254.5L212.578,260&quot; id=&quot;L_iptables_traefik_0&quot; class=&quot;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&quot; style=&quot;&quot; data-edge=&quot;true&quot; data-et=&quot;edge&quot; data-id=&quot;L_iptables_traefik_0&quot; data-points=&quot;W3sieCI6MjUwLjIzMzAzMjIyNjU2MjUsInkiOjE5MH0seyJ4IjoyMTIuNTc4MTI1LCJ5IjoyMjd9LHsieCI6MjEyLjU3ODEyNSwieSI6MjY0fV0=&quot; marker-end=&quot;url(#mermaid-1_flowchart-v2-pointEnd)&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M166.254,318L155.674,324.167C145.094,330.333,123.934,342.667,113.354,354.333C102.773,366,102.773,377,102.773,382.5L102.773,388&quot; id=&quot;L_traefik_app_0&quot; class=&quot;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&quot; style=&quot;&quot; data-edge=&quot;true&quot; data-et=&quot;edge&quot; data-id=&quot;L_traefik_app_0&quot; data-points=&quot;W3sieCI6MTY2LjI1NDI3MjQ2MDkzNzUsInkiOjMxOH0seyJ4IjoxMDIuNzczNDM3NSwieSI6MzU1fSx7IngiOjEwMi43NzM0Mzc1LCJ5IjozOTJ9XQ==&quot; marker-end=&quot;url(#mermaid-1_flowchart-v2-pointEnd)&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M258.902,318L269.482,324.167C280.062,330.333,301.223,342.667,311.803,354.333C322.383,366,322.383,377,322.383,382.5L322.383,388&quot; id=&quot;L_traefik_logs_0&quot; class=&quot;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&quot; style=&quot;&quot; data-edge=&quot;true&quot; data-et=&quot;edge&quot; data-id=&quot;L_traefik_logs_0&quot; data-points=&quot;W3sieCI6MjU4LjkwMTk3NzUzOTA2MjUsInkiOjMxOH0seyJ4IjozMjIuMzgyODEyNSwieSI6MzU1fSx7IngiOjMyMi4zODI4MTI1LCJ5IjozOTJ9XQ==&quot; marker-end=&quot;url(#mermaid-1_flowchart-v2-pointEnd)&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M322.383,446L322.383,452.167C322.383,458.333,322.383,470.667,328.183,482.533C333.983,494.399,345.584,505.798,351.384,511.497L357.185,517.196&quot; id=&quot;L_logs_fail2ban_0&quot; class=&quot;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&quot; style=&quot;&quot; data-edge=&quot;true&quot; data-et=&quot;edge&quot; data-id=&quot;L_logs_fail2ban_0&quot; data-points=&quot;W3sieCI6MzIyLjM4MjgxMjUsInkiOjQ0Nn0seyJ4IjozMjIuMzgyODEyNSwieSI6NDgzfSx7IngiOjM2MC4wMzc3MTk3MjY1NjI1LCJ5Ijo1MjB9XQ==&quot; marker-end=&quot;url(#mermaid-1_flowchart-v2-pointEnd)&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M414.994,520L421.269,513.833C427.545,507.667,440.097,495.333,446.373,478.5C452.648,461.667,452.648,440.333,452.648,419C452.648,397.667,452.648,376.333,452.648,355C452.648,333.667,452.648,312.333,452.648,291C452.648,269.667,452.648,248.333,436.419,231.729C420.189,215.125,387.729,203.25,371.499,197.312L355.269,191.374&quot; id=&quot;L_fail2ban_iptables_0&quot; class=&quot;edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link&quot; style=&quot;&quot; data-edge=&quot;true&quot; data-et=&quot;edge&quot; data-id=&quot;L_fail2ban_iptables_0&quot; data-points=&quot;W3sieCI6NDE0Ljk5MzUzMDI3MzQzNzUsInkiOjUyMH0seyJ4Ijo0NTIuNjQ4NDM3NSwieSI6NDgzfSx7IngiOjQ1Mi42NDg0Mzc1LCJ5Ijo0MTl9LHsieCI6NDUyLjY0ODQzNzUsInkiOjM1NX0seyJ4Ijo0NTIuNjQ4NDM3NSwieSI6MjkxfSx7IngiOjQ1Mi42NDg0Mzc1LCJ5IjoyMjd9LHsieCI6MzUxLjUxMjY5NTMxMjUsInkiOjE5MH1d&quot; marker-end=&quot;url(#mermaid-1_flowchart-v2-pointEnd)&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabels&quot;&gt;&lt;g class=&quot;edgeLabel&quot; transform=&quot;translate(277.7109375, 99)&quot;&gt;&lt;g class=&quot;label&quot; data-id=&quot;L_client_iptables_0&quot; transform=&quot;translate(-52.4921875, -12)&quot;&gt;&lt;foreignObject width=&quot;104.984375&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; class=&quot;labelBkg&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;edgeLabel&quot;&gt;&lt;p&gt;HTTP Request&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot; transform=&quot;translate(212.578125, 227)&quot;&gt;&lt;g class=&quot;label&quot; data-id=&quot;L_iptables_traefik_0&quot; transform=&quot;translate(-86.015625, -12)&quot;&gt;&lt;foreignObject width=&quot;172.03125&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; class=&quot;labelBkg&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;edgeLabel&quot;&gt;&lt;p&gt;Check f2b-traefik chain&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot; transform=&quot;translate(102.7734375, 355)&quot;&gt;&lt;g class=&quot;label&quot; data-id=&quot;L_traefik_app_0&quot; transform=&quot;translate(-52.9921875, -12)&quot;&gt;&lt;foreignObject width=&quot;105.984375&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; class=&quot;labelBkg&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;edgeLabel&quot;&gt;&lt;p&gt;Route request&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot; transform=&quot;translate(322.3828125, 355)&quot;&gt;&lt;g class=&quot;label&quot; data-id=&quot;L_traefik_logs_0&quot; transform=&quot;translate(-58.140625, -12)&quot;&gt;&lt;foreignObject width=&quot;116.28125&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; class=&quot;labelBkg&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;edgeLabel&quot;&gt;&lt;p&gt;Log with real IP&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot; transform=&quot;translate(322.3828125, 483)&quot;&gt;&lt;g class=&quot;label&quot; data-id=&quot;L_logs_fail2ban_0&quot; transform=&quot;translate(-30.140625, -12)&quot;&gt;&lt;foreignObject width=&quot;60.28125&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; class=&quot;labelBkg&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;edgeLabel&quot;&gt;&lt;p&gt;Monitor&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;edgeLabel&quot; transform=&quot;translate(452.6484375, 355)&quot;&gt;&lt;g class=&quot;label&quot; data-id=&quot;L_fail2ban_iptables_0&quot; transform=&quot;translate(-52.125, -12)&quot;&gt;&lt;foreignObject width=&quot;104.25&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; class=&quot;labelBkg&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;edgeLabel&quot;&gt;&lt;p&gt;Add ban rules&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;nodes&quot;&gt;&lt;g class=&quot;node default client&quot; id=&quot;flowchart-client-0&quot; transform=&quot;translate(277.7109375, 35)&quot;&gt;&lt;rect class=&quot;basic label-container&quot; style=&quot;fill:#f5933033 !important;stroke:#f59330 !important;stroke-width:1.5px !important&quot; x=&quot;-72.0078125&quot; y=&quot;-27&quot; width=&quot;144.015625&quot; height=&quot;54&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; style=&quot;&quot; transform=&quot;translate(-42.0078125, -12)&quot;&gt;&lt;rect&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;84.015625&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;nodeLabel&quot;&gt;&lt;p&gt;Client/User&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;node default iptables&quot; id=&quot;flowchart-iptables-1&quot; transform=&quot;translate(277.7109375, 163)&quot;&gt;&lt;rect class=&quot;basic label-container&quot; style=&quot;fill:#2563eb33 !important;stroke:#2563eb !important;stroke-width:1.5px !important&quot; x=&quot;-79.2578125&quot; y=&quot;-27&quot; width=&quot;158.515625&quot; height=&quot;54&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; style=&quot;&quot; transform=&quot;translate(-49.2578125, -12)&quot;&gt;&lt;rect&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;98.515625&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;nodeLabel&quot;&gt;&lt;p&gt;Host iptables&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;node default traefik&quot; id=&quot;flowchart-traefik-3&quot; transform=&quot;translate(212.578125, 291)&quot;&gt;&lt;rect class=&quot;basic label-container&quot; style=&quot;fill:#10b98133 !important;stroke:#10b981 !important;stroke-width:1.5px !important&quot; x=&quot;-94.40625&quot; y=&quot;-27&quot; width=&quot;188.8125&quot; height=&quot;54&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; style=&quot;&quot; transform=&quot;translate(-64.40625, -12)&quot;&gt;&lt;rect&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;128.8125&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;nodeLabel&quot;&gt;&lt;p&gt;Traefik Container&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;node default app&quot; id=&quot;flowchart-app-5&quot; transform=&quot;translate(102.7734375, 419)&quot;&gt;&lt;rect class=&quot;basic label-container&quot; style=&quot;fill:#10b98133 !important;stroke:#10b981 !important;stroke-width:1.5px !important&quot; x=&quot;-94.7734375&quot; y=&quot;-27&quot; width=&quot;189.546875&quot; height=&quot;54&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; style=&quot;&quot; transform=&quot;translate(-64.7734375, -12)&quot;&gt;&lt;rect&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;129.546875&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;nodeLabel&quot;&gt;&lt;p&gt;Web Applications&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;node default logs&quot; id=&quot;flowchart-logs-7&quot; transform=&quot;translate(322.3828125, 419)&quot;&gt;&lt;rect class=&quot;basic label-container&quot; style=&quot;fill:#8b5cf633 !important;stroke:#8b5cf6 !important;stroke-width:1.5px !important&quot; x=&quot;-74.8359375&quot; y=&quot;-27&quot; width=&quot;149.671875&quot; height=&quot;54&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; style=&quot;&quot; transform=&quot;translate(-44.8359375, -12)&quot;&gt;&lt;rect&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;89.671875&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;nodeLabel&quot;&gt;&lt;p&gt;Access Logs&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;g class=&quot;node default fail2ban&quot; id=&quot;flowchart-fail2ban-9&quot; transform=&quot;translate(387.515625, 547)&quot;&gt;&lt;rect class=&quot;basic label-container&quot; style=&quot;fill:#8b5cf633 !important;stroke:#8b5cf6 !important;stroke-width:1.5px !important&quot; x=&quot;-61.9765625&quot; y=&quot;-27&quot; width=&quot;123.953125&quot; height=&quot;54&quot;&gt;&lt;/rect&gt;&lt;g class=&quot;label&quot; style=&quot;&quot; transform=&quot;translate(-31.9765625, -12)&quot;&gt;&lt;rect&gt;&lt;/rect&gt;&lt;foreignObject width=&quot;63.953125&quot; height=&quot;24&quot;&gt;&lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot; style=&quot;display:table-cell;white-space:nowrap;line-height:1.5;max-width:200px;text-align:center&quot;&gt;&lt;span class=&quot;nodeLabel&quot;&gt;&lt;p&gt;Fail2Ban&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;
&lt;p&gt;This approach ensures bans are effective even with Docker&apos;s network abstractions.&lt;/p&gt;
&lt;h1 id=&quot;testing-the-security-setup&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#testing-the-security-setup&quot;&gt;Testing the Security Setup&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;After configuring all components, it&apos;s important to test your setup:&lt;/p&gt;
&lt;h2 id=&quot;test-ufw&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#test-ufw&quot;&gt;Test UFW&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; ufw status verbose&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;test-psad&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#test-psad&quot;&gt;Test PSAD&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; psad --Status&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;test-fail2ban&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#test-fail2ban&quot;&gt;Test Fail2Ban&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; fail2ban-client status
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; fail2ban-client status traefik-auth
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; fail2ban-client status traefik-ratelimit&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;verify-iptables-rules&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#verify-iptables-rules&quot;&gt;Verify iptables Rules&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; iptables -L f2b-traefik -n&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;maintenance-and-monitoring&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#maintenance-and-monitoring&quot;&gt;Maintenance and Monitoring&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Regular maintenance is crucial for keeping your security stack effective:&lt;/p&gt;
&lt;h2 id=&quot;check-logs-regularly&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#check-logs-regularly&quot;&gt;Check Logs Regularly&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; tail -f /var/log/fail2ban.log
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; tail -f /var/log/psad/psad.log&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;update-signatures&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#update-signatures&quot;&gt;Update Signatures&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; psad --sig-update&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;unban-ips-when-needed&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#unban-ips-when-needed&quot;&gt;Unban IPs When Needed&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; fail2ban-client set traefik-auth unbanip 192.168.1.100&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;review-banned-ips-periodically&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#review-banned-ips-periodically&quot;&gt;Review Banned IPs Periodically&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; fail2ban-client status traefik-auth&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;visualizing-the-attack-scenarios&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#visualizing-the-attack-scenarios&quot;&gt;Visualizing the Attack Scenarios&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;To better understand how these components interact during an attack, let&apos;s visualize two common scenarios:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Port Scan Attack&lt;/strong&gt;: An attacker scans for open ports on your server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Brute Force Login&lt;/strong&gt;: An attacker tries to guess login credentials for your applications.&lt;/li&gt;
&lt;/ol&gt;
&lt;svg id=&quot;mermaid-2&quot; width=&quot;100%&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; viewBox=&quot;-50 -10 1434 929&quot; role=&quot;graphics-document document&quot; aria-roledescription=&quot;sequence&quot;&gt;&lt;g&gt;&lt;rect x=&quot;1184&quot; y=&quot;843&quot; fill=&quot;#eaeaea&quot; stroke=&quot;#666&quot; width=&quot;150&quot; height=&quot;65&quot; name=&quot;IPT&quot; rx=&quot;3&quot; ry=&quot;3&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;1259&quot; y=&quot;875.5&quot; dominant-baseline=&quot;central&quot; alignment-baseline=&quot;central&quot;&gt;&lt;tspan x=&quot;1259&quot; dy=&quot;0&quot;&gt;iptables&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g&gt;&lt;rect x=&quot;834&quot; y=&quot;843&quot; fill=&quot;#eaeaea&quot; stroke=&quot;#666&quot; width=&quot;150&quot; height=&quot;65&quot; name=&quot;F2B&quot; rx=&quot;3&quot; ry=&quot;3&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;909&quot; y=&quot;875.5&quot; dominant-baseline=&quot;central&quot; alignment-baseline=&quot;central&quot;&gt;&lt;tspan x=&quot;909&quot; dy=&quot;0&quot;&gt;Fail2Ban&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g&gt;&lt;rect x=&quot;634&quot; y=&quot;843&quot; fill=&quot;#eaeaea&quot; stroke=&quot;#666&quot; width=&quot;150&quot; height=&quot;65&quot; name=&quot;Traefik&quot; rx=&quot;3&quot; ry=&quot;3&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;709&quot; y=&quot;875.5&quot; dominant-baseline=&quot;central&quot; alignment-baseline=&quot;central&quot;&gt;&lt;tspan x=&quot;709&quot; dy=&quot;0&quot;&gt;Traefik Proxy&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g&gt;&lt;rect x=&quot;434&quot; y=&quot;843&quot; fill=&quot;#eaeaea&quot; stroke=&quot;#666&quot; width=&quot;150&quot; height=&quot;65&quot; name=&quot;PSAD&quot; rx=&quot;3&quot; ry=&quot;3&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;509&quot; y=&quot;875.5&quot; dominant-baseline=&quot;central&quot; alignment-baseline=&quot;central&quot;&gt;&lt;tspan x=&quot;509&quot; dy=&quot;0&quot;&gt;PSAD&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g&gt;&lt;rect x=&quot;234&quot; y=&quot;843&quot; fill=&quot;#eaeaea&quot; stroke=&quot;#666&quot; width=&quot;150&quot; height=&quot;65&quot; name=&quot;UFW&quot; rx=&quot;3&quot; ry=&quot;3&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;309&quot; y=&quot;875.5&quot; dominant-baseline=&quot;central&quot; alignment-baseline=&quot;central&quot;&gt;&lt;tspan x=&quot;309&quot; dy=&quot;0&quot;&gt;UFW Firewall&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g&gt;&lt;rect x=&quot;0&quot; y=&quot;843&quot; fill=&quot;#eaeaea&quot; stroke=&quot;#666&quot; width=&quot;150&quot; height=&quot;65&quot; name=&quot;Client&quot; rx=&quot;3&quot; ry=&quot;3&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;75&quot; y=&quot;875.5&quot; dominant-baseline=&quot;central&quot; alignment-baseline=&quot;central&quot;&gt;&lt;tspan x=&quot;75&quot; dy=&quot;0&quot;&gt;Attacker&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g&gt;&lt;line id=&quot;actor5&quot; x1=&quot;1259&quot; y1=&quot;65&quot; x2=&quot;1259&quot; y2=&quot;843&quot; stroke-width=&quot;0.5px&quot; stroke=&quot;#999&quot; name=&quot;IPT&quot;&gt;&lt;/line&gt;&lt;g id=&quot;root-5&quot;&gt;&lt;rect x=&quot;1184&quot; y=&quot;0&quot; fill=&quot;#eaeaea&quot; stroke=&quot;#666&quot; width=&quot;150&quot; height=&quot;65&quot; name=&quot;IPT&quot; rx=&quot;3&quot; ry=&quot;3&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;1259&quot; y=&quot;32.5&quot; dominant-baseline=&quot;central&quot; alignment-baseline=&quot;central&quot;&gt;&lt;tspan x=&quot;1259&quot; dy=&quot;0&quot;&gt;iptables&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;/g&gt;&lt;g&gt;&lt;line id=&quot;actor4&quot; x1=&quot;909&quot; y1=&quot;65&quot; x2=&quot;909&quot; y2=&quot;843&quot; stroke-width=&quot;0.5px&quot; stroke=&quot;#999&quot; name=&quot;F2B&quot;&gt;&lt;/line&gt;&lt;g id=&quot;root-4&quot;&gt;&lt;rect x=&quot;834&quot; y=&quot;0&quot; fill=&quot;#eaeaea&quot; stroke=&quot;#666&quot; width=&quot;150&quot; height=&quot;65&quot; name=&quot;F2B&quot; rx=&quot;3&quot; ry=&quot;3&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;909&quot; y=&quot;32.5&quot; dominant-baseline=&quot;central&quot; alignment-baseline=&quot;central&quot;&gt;&lt;tspan x=&quot;909&quot; dy=&quot;0&quot;&gt;Fail2Ban&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;/g&gt;&lt;g&gt;&lt;line id=&quot;actor3&quot; x1=&quot;709&quot; y1=&quot;65&quot; x2=&quot;709&quot; y2=&quot;843&quot; stroke-width=&quot;0.5px&quot; stroke=&quot;#999&quot; name=&quot;Traefik&quot;&gt;&lt;/line&gt;&lt;g id=&quot;root-3&quot;&gt;&lt;rect x=&quot;634&quot; y=&quot;0&quot; fill=&quot;#eaeaea&quot; stroke=&quot;#666&quot; width=&quot;150&quot; height=&quot;65&quot; name=&quot;Traefik&quot; rx=&quot;3&quot; ry=&quot;3&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;709&quot; y=&quot;32.5&quot; dominant-baseline=&quot;central&quot; alignment-baseline=&quot;central&quot;&gt;&lt;tspan x=&quot;709&quot; dy=&quot;0&quot;&gt;Traefik Proxy&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;/g&gt;&lt;g&gt;&lt;line id=&quot;actor2&quot; x1=&quot;509&quot; y1=&quot;65&quot; x2=&quot;509&quot; y2=&quot;843&quot; stroke-width=&quot;0.5px&quot; stroke=&quot;#999&quot; name=&quot;PSAD&quot;&gt;&lt;/line&gt;&lt;g id=&quot;root-2&quot;&gt;&lt;rect x=&quot;434&quot; y=&quot;0&quot; fill=&quot;#eaeaea&quot; stroke=&quot;#666&quot; width=&quot;150&quot; height=&quot;65&quot; name=&quot;PSAD&quot; rx=&quot;3&quot; ry=&quot;3&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;509&quot; y=&quot;32.5&quot; dominant-baseline=&quot;central&quot; alignment-baseline=&quot;central&quot;&gt;&lt;tspan x=&quot;509&quot; dy=&quot;0&quot;&gt;PSAD&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;/g&gt;&lt;g&gt;&lt;line id=&quot;actor1&quot; x1=&quot;309&quot; y1=&quot;65&quot; x2=&quot;309&quot; y2=&quot;843&quot; stroke-width=&quot;0.5px&quot; stroke=&quot;#999&quot; name=&quot;UFW&quot;&gt;&lt;/line&gt;&lt;g id=&quot;root-1&quot;&gt;&lt;rect x=&quot;234&quot; y=&quot;0&quot; fill=&quot;#eaeaea&quot; stroke=&quot;#666&quot; width=&quot;150&quot; height=&quot;65&quot; name=&quot;UFW&quot; rx=&quot;3&quot; ry=&quot;3&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;309&quot; y=&quot;32.5&quot; dominant-baseline=&quot;central&quot; alignment-baseline=&quot;central&quot;&gt;&lt;tspan x=&quot;309&quot; dy=&quot;0&quot;&gt;UFW Firewall&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;/g&gt;&lt;g&gt;&lt;line id=&quot;actor0&quot; x1=&quot;75&quot; y1=&quot;65&quot; x2=&quot;75&quot; y2=&quot;843&quot; stroke-width=&quot;0.5px&quot; stroke=&quot;#999&quot; name=&quot;Client&quot;&gt;&lt;/line&gt;&lt;g id=&quot;root-0&quot;&gt;&lt;rect x=&quot;0&quot; y=&quot;0&quot; fill=&quot;#eaeaea&quot; stroke=&quot;#666&quot; width=&quot;150&quot; height=&quot;65&quot; name=&quot;Client&quot; rx=&quot;3&quot; ry=&quot;3&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;75&quot; y=&quot;32.5&quot; dominant-baseline=&quot;central&quot; alignment-baseline=&quot;central&quot;&gt;&lt;tspan x=&quot;75&quot; dy=&quot;0&quot;&gt;Attacker&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;/g&gt;&lt;g&gt;&lt;/g&gt;&lt;defs&gt;&lt;symbol id=&quot;computer&quot; width=&quot;24&quot; height=&quot;24&quot;&gt;&lt;path transform=&quot;scale(.5)&quot; d=&quot;M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z&quot;&gt;&lt;/path&gt;&lt;/symbol&gt;&lt;/defs&gt;&lt;defs&gt;&lt;symbol id=&quot;database&quot; fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot;&gt;&lt;path transform=&quot;scale(.5)&quot; d=&quot;M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z&quot;&gt;&lt;/path&gt;&lt;/symbol&gt;&lt;/defs&gt;&lt;defs&gt;&lt;symbol id=&quot;clock&quot; width=&quot;24&quot; height=&quot;24&quot;&gt;&lt;path transform=&quot;scale(.5)&quot; d=&quot;M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z&quot;&gt;&lt;/path&gt;&lt;/symbol&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id=&quot;arrowhead&quot; refX=&quot;7.9&quot; refY=&quot;5&quot; markerUnits=&quot;userSpaceOnUse&quot; markerWidth=&quot;12&quot; markerHeight=&quot;12&quot; orient=&quot;auto-start-reverse&quot;&gt;&lt;path d=&quot;M -1 0 L 10 5 L 0 10 z&quot;&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id=&quot;crosshead&quot; markerWidth=&quot;15&quot; markerHeight=&quot;8&quot; orient=&quot;auto&quot; refX=&quot;4&quot; refY=&quot;4.5&quot;&gt;&lt;path fill=&quot;none&quot; stroke=&quot;#000000&quot; stroke-width=&quot;1pt&quot; d=&quot;M 1,2 L 6,7 M 6,2 L 1,7&quot;&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id=&quot;filled-head&quot; refX=&quot;15.5&quot; refY=&quot;7&quot; markerWidth=&quot;20&quot; markerHeight=&quot;28&quot; orient=&quot;auto&quot;&gt;&lt;path d=&quot;M 18,7 L9,13 L14,7 L9,1 Z&quot;&gt;&lt;/path&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;defs&gt;&lt;marker id=&quot;sequencenumber&quot; refX=&quot;15&quot; refY=&quot;15&quot; markerWidth=&quot;60&quot; markerHeight=&quot;40&quot; orient=&quot;auto&quot;&gt;&lt;circle cx=&quot;15&quot; cy=&quot;15&quot; r=&quot;6&quot;&gt;&lt;/circle&gt;&lt;/marker&gt;&lt;/defs&gt;&lt;g&gt;&lt;rect x=&quot;50&quot; y=&quot;75&quot; fill=&quot;#EDF2AE&quot; stroke=&quot;#666&quot; width=&quot;1234&quot; height=&quot;42&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;667&quot; y=&quot;80&quot; text-anchor=&quot;middle&quot; dominant-baseline=&quot;middle&quot; alignment-baseline=&quot;middle&quot; dy=&quot;1em&quot;&gt;&lt;tspan x=&quot;667&quot;&gt;Scenario 1: Port Scan Attack&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;g&gt;&lt;rect x=&quot;50&quot; y=&quot;427&quot; fill=&quot;#EDF2AE&quot; stroke=&quot;#666&quot; width=&quot;1234&quot; height=&quot;42&quot;&gt;&lt;/rect&gt;&lt;text x=&quot;667&quot; y=&quot;432&quot; text-anchor=&quot;middle&quot; dominant-baseline=&quot;middle&quot; alignment-baseline=&quot;middle&quot; dy=&quot;1em&quot;&gt;&lt;tspan x=&quot;667&quot;&gt;Scenario 2: Brute Force Login&lt;/tspan&gt;&lt;/text&gt;&lt;/g&gt;&lt;text x=&quot;191&quot; y=&quot;132&quot; text-anchor=&quot;middle&quot; dominant-baseline=&quot;middle&quot; alignment-baseline=&quot;middle&quot; dy=&quot;1em&quot;&gt;Port Scan Activity&lt;/text&gt;&lt;line x1=&quot;76&quot; y1=&quot;171&quot; x2=&quot;305&quot; y2=&quot;171&quot; stroke-width=&quot;2&quot; stroke=&quot;none&quot; marker-end=&quot;url(#arrowhead)&quot;&gt;&lt;/line&gt;&lt;text x=&quot;408&quot; y=&quot;186&quot; text-anchor=&quot;middle&quot; dominant-baseline=&quot;middle&quot; alignment-baseline=&quot;middle&quot; dy=&quot;1em&quot;&gt;Logs via iptables&lt;/text&gt;&lt;line x1=&quot;310&quot; y1=&quot;225&quot; x2=&quot;505&quot; y2=&quot;225&quot; stroke-width=&quot;2&quot; stroke=&quot;none&quot; marker-end=&quot;url(#arrowhead)&quot;&gt;&lt;/line&gt;&lt;text x=&quot;510&quot; y=&quot;240&quot; text-anchor=&quot;middle&quot; dominant-baseline=&quot;middle&quot; alignment-baseline=&quot;middle&quot; dy=&quot;1em&quot;&gt;Analyzes patterns&lt;/text&gt;&lt;path d=&quot;M 510,279 C 570,269 570,309 510,299&quot; stroke-width=&quot;2&quot; stroke=&quot;none&quot; marker-end=&quot;url(#arrowhead)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;883&quot; y=&quot;324&quot; text-anchor=&quot;middle&quot; dominant-baseline=&quot;middle&quot; alignment-baseline=&quot;middle&quot; dy=&quot;1em&quot;&gt;Creates block rule&lt;/text&gt;&lt;line x1=&quot;510&quot; y1=&quot;363&quot; x2=&quot;1255&quot; y2=&quot;363&quot; stroke-width=&quot;2&quot; stroke=&quot;none&quot; marker-end=&quot;url(#arrowhead)&quot;&gt;&lt;/line&gt;&lt;text x=&quot;669&quot; y=&quot;378&quot; text-anchor=&quot;middle&quot; dominant-baseline=&quot;middle&quot; alignment-baseline=&quot;middle&quot; dy=&quot;1em&quot;&gt;Traffic blocked&lt;/text&gt;&lt;line x1=&quot;1258&quot; y1=&quot;417&quot; x2=&quot;79&quot; y2=&quot;417&quot; stroke-width=&quot;2&quot; stroke=&quot;none&quot; marker-end=&quot;url(#arrowhead)&quot;&gt;&lt;/line&gt;&lt;text x=&quot;191&quot; y=&quot;484&quot; text-anchor=&quot;middle&quot; dominant-baseline=&quot;middle&quot; alignment-baseline=&quot;middle&quot; dy=&quot;1em&quot;&gt;Traffic to allowed port&lt;/text&gt;&lt;line x1=&quot;76&quot; y1=&quot;523&quot; x2=&quot;305&quot; y2=&quot;523&quot; stroke-width=&quot;2&quot; stroke=&quot;none&quot; marker-end=&quot;url(#arrowhead)&quot;&gt;&lt;/line&gt;&lt;text x=&quot;508&quot; y=&quot;538&quot; text-anchor=&quot;middle&quot; dominant-baseline=&quot;middle&quot; alignment-baseline=&quot;middle&quot; dy=&quot;1em&quot;&gt;Pass through&lt;/text&gt;&lt;line x1=&quot;310&quot; y1=&quot;577&quot; x2=&quot;705&quot; y2=&quot;577&quot; stroke-width=&quot;2&quot; stroke=&quot;none&quot; marker-end=&quot;url(#arrowhead)&quot;&gt;&lt;/line&gt;&lt;text x=&quot;710&quot; y=&quot;592&quot; text-anchor=&quot;middle&quot; dominant-baseline=&quot;middle&quot; alignment-baseline=&quot;middle&quot; dy=&quot;1em&quot;&gt;Logs 401 errors&lt;/text&gt;&lt;path d=&quot;M 710,631 C 770,621 770,661 710,651&quot; stroke-width=&quot;2&quot; stroke=&quot;none&quot; marker-end=&quot;url(#arrowhead)&quot;&gt;&lt;/path&gt;&lt;text x=&quot;808&quot; y=&quot;676&quot; text-anchor=&quot;middle&quot; dominant-baseline=&quot;middle&quot; alignment-baseline=&quot;middle&quot; dy=&quot;1em&quot;&gt;Log analysis&lt;/text&gt;&lt;line x1=&quot;710&quot; y1=&quot;715&quot; x2=&quot;905&quot; y2=&quot;715&quot; stroke-width=&quot;2&quot; stroke=&quot;none&quot; marker-end=&quot;url(#arrowhead)&quot;&gt;&lt;/line&gt;&lt;text x=&quot;1083&quot; y=&quot;730&quot; text-anchor=&quot;middle&quot; dominant-baseline=&quot;middle&quot; alignment-baseline=&quot;middle&quot; dy=&quot;1em&quot;&gt;Creates block rule in f2b-traefik chain&lt;/text&gt;&lt;line x1=&quot;910&quot; y1=&quot;769&quot; x2=&quot;1255&quot; y2=&quot;769&quot; stroke-width=&quot;2&quot; stroke=&quot;none&quot; marker-end=&quot;url(#arrowhead)&quot;&gt;&lt;/line&gt;&lt;text x=&quot;669&quot; y=&quot;784&quot; text-anchor=&quot;middle&quot; dominant-baseline=&quot;middle&quot; alignment-baseline=&quot;middle&quot; dy=&quot;1em&quot;&gt;Traffic blocked&lt;/text&gt;&lt;line x1=&quot;1258&quot; y1=&quot;823&quot; x2=&quot;79&quot; y2=&quot;823&quot; stroke-width=&quot;2&quot; stroke=&quot;none&quot; marker-end=&quot;url(#arrowhead)&quot;&gt;&lt;/line&gt;&lt;/svg&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Hardening a reverse proxy like Traefik on a public host isn’t a set-it-and-forget-it operation. This layered approach - combining firewall rules, intrusion detection, and log-based banning - ensures you&apos;re actively defending against real-world threats.&lt;/p&gt;
&lt;p&gt;If you&apos;re running Docker in production or even just experimenting in a homelab, these practices are well worth the effort.&lt;/p&gt;
&lt;p&gt;Let me know if you have any questions or if you want to share your own security setups! If you found this post helpful, consider sharing it with others who might benefit from it. Happy homelabbing!&lt;/p&gt;
&lt;h1 id=&quot;additional-resources&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#additional-resources&quot;&gt;Additional Resources&lt;/a&gt;&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/imthenachoman/How-To-Secure-A-Linux-Server&quot;&gt;How to Secure a Linux Server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Exposing Homelab Services with Cloudflare Tunnels</title><link>https://yashagarwal.in/notes/homelab-using-cloudflared/</link><guid isPermaLink="true">https://yashagarwal.in/notes/homelab-using-cloudflared/</guid><description>Learn to expose homelab services securely with Cloudflare Tunnels, leveraging Traefik and Docker for robust external access and HTTPS.</description><pubDate>Sun, 11 May 2025 07:49:47 GMT</pubDate><content:encoded>&lt;p&gt;I recently purchased a new MacMini to serve as my primary workstation. While setting up a homelab on this was a no-brainer, I wanted to ensure that I am able to access the services outside my home network. Unlike my previous attempts at homelabbing, this time, I was equipped with past experiences and a beefier machine to keep me engaged. Key objectives included enforcing HTTPS for all traffic (both local and external), and avoiding direct exposure of router ports. Since my domain is managed by Cloudflare DNS, I decided to leverage Cloudflare Tunnels for external access. This log documents the steps taken and solutions to common hiccups for future reference.&lt;/p&gt;
&lt;h1 id=&quot;core-design&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#core-design&quot;&gt;Core Design&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The setup relies on two main traffic flows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;External Access:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;User navigates to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;service.mydomain.com&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;DNS resolves via Cloudflare, directing the request through a Cloudflare Tunnel.&lt;/li&gt;
&lt;li&gt;The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;cloudflared&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; client (Docker container) on my workstation receives this traffic.&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;cloudflared&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; forwards the request to Traefik (another Docker container) over the internal Docker network (HTTPS).&lt;/li&gt;
&lt;li&gt;Traefik, acting as a reverse proxy, handles SSL termination using Let&apos;s Encrypt certificates and routes the request to the appropriate backend application container.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Internal (LAN) Access:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;User navigates to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;service.mydomain.com&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;My local router&apos;s custom DNS entry resolves the domain directly to my workstation&apos;s local IP.&lt;/li&gt;
&lt;li&gt;The browser connects directly to Traefik (listening on port 443) on the workstation.&lt;/li&gt;
&lt;li&gt;Traefik handles SSL and routes to the backend application.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;cloudflare-configuration---tokens-and-tunnels&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#cloudflare-configuration---tokens-and-tunnels&quot;&gt;Cloudflare Configuration - Tokens and Tunnels&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&quot;cloudflare-api-token-for-traefik-dns-01-challenge&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#cloudflare-api-token-for-traefik-dns-01-challenge&quot;&gt;Cloudflare API Token for Traefik (DNS-01 Challenge)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Traefik needs a Cloudflare API token to automatically manage Let&apos;s Encrypt certificates using Cloudflare&apos;s DNS. Here&apos;s how to create one:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to Cloudflare Dashboard -&gt; My Profile -&gt; API Tokens.&lt;/li&gt;
&lt;li&gt;Click &quot;Create Token.&quot;&lt;/li&gt;
&lt;li&gt;Choose the &quot;Edit zone DNS&quot; template.&lt;/li&gt;
&lt;li&gt;Set the following Permissions: &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Zone - DNS - Edit&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Set Zone Resources: &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Include - All zones from an account&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Generate the token and store it securely. This will be needed in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;docker-compose.yml&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;cloudflare-tunnel-creation&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#cloudflare-tunnel-creation&quot;&gt;Cloudflare Tunnel Creation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To establish a secure connection from Cloudflare to my local network, I created a Cloudflare Tunnel. This tunnel acts as a secure conduit for traffic between Cloudflare&apos;s edge and my local &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;cloudflared&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; client.&lt;/p&gt;
&lt;p&gt;Since I wanted to run &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;cloudflared&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; inside Docker on my main server, I used a separate machine to create the tunnel. This avoids needing to install &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;cloudflared&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; directly on my workstation.&lt;/p&gt;
&lt;p&gt;On the separate machine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;cloudflared login&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; - Authenticated with Cloudflare and selected &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;mydomain.com&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;cloudflared tunnel create homelab-main-tunnel&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; - Created a new tunnel.&lt;/li&gt;
&lt;li&gt;Noted the &lt;strong&gt;Tunnel ID&lt;/strong&gt; (UUID format) provided.&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;cloudflared tunnel token homelab-main-tunnel&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; - Generated the specific token for this tunnel.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Keep this token handy; it will be used in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;docker-compose.yml&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file for the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;cloudflared&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; service.&lt;/p&gt;
&lt;h1 id=&quot;local-project-structure-and-traefik-configuration&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#local-project-structure-and-traefik-configuration&quot;&gt;Local Project Structure and Traefik Configuration&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I set up the following directory structure on my workstation:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;~/homelab/&lt;/span&gt;
&lt;span&gt;├── docker-compose.yml&lt;/span&gt;
&lt;span&gt;├── traefik/&lt;/span&gt;
&lt;span&gt;│   ├── traefik.yml        # Traefik static configuration&lt;/span&gt;
&lt;span&gt;│   ├── acme.json          # For Let&apos;s Encrypt certificate storage&lt;/span&gt;
&lt;span&gt;│   └── logs/              # Persistent logs for Traefik&lt;/span&gt;
&lt;span&gt;└── cloudflared/&lt;/span&gt;
&lt;span&gt;    └── config.yml         # Ingress rules for the cloudflared client&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;traefik-static-configuration&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#traefik-static-configuration&quot;&gt;Traefik Static Configuration&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This file defines Traefik&apos;s fundamental settings, entrypoints, and certificate resolvers.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;global&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  checkNewVersion&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  sendAnonymousUsage&lt;/span&gt;: false # Disabled for privacy
 
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;api&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  dashboard&lt;/span&gt;: true # Enable the Traefik web UI
 
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;log&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  level&lt;/span&gt;: INFO
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;accessLog&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  filePath&lt;/span&gt;: &quot;/var/log/traefik/access.log&quot;
 
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;entryPoints&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  web&lt;/span&gt;: # HTTP entrypoint (port 80)
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    address&lt;/span&gt;: &quot;:80&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    http&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      redirections&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;        entryPoint&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;          to&lt;/span&gt;: websecure
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;          scheme&lt;/span&gt;: https
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    # docker network inspect proxy_network&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    # IPAM -&gt; Config -&gt; Subnet&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    forwardedHeaders&lt;/span&gt;: # Trust headers from known internal proxies
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      trustedIPs&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        - &lt;/span&gt;&quot;172.16.0.0/12&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        - &lt;/span&gt;&quot;192.168.0.0/16&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        - &lt;/span&gt;&quot;10.0.0.0/8&quot;
 
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  websecure&lt;/span&gt;: # HTTPS entrypoint (port 443)
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    address&lt;/span&gt;: &quot;:443&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    http&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      tls&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;        certResolver&lt;/span&gt;: cloudflareResolver
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;        domains&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;          - &lt;/span&gt;main: &quot;mydomain.com&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;            sans&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;              - &lt;/span&gt;&quot;*.mydomain.com&quot; # Wildcard certificate for subdomains
 
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;providers&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  docker&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    exposedByDefault&lt;/span&gt;: false # Only manage containers with explicit Traefik labels
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    network&lt;/span&gt;: proxy_network # The Docker network Traefik will monitor
 
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;certificatesResolvers&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  cloudflareResolver&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    acme&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      email&lt;/span&gt;: &quot;my-email@example.com&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      storage&lt;/span&gt;: &quot;/etc/traefik/acme.json&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      dnsChallenge&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;        provider&lt;/span&gt;: cloudflare&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;lets-encrypt-storage&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#lets-encrypt-storage&quot;&gt;Let&apos;s Encrypt Storage&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Created an empty file and set permissions for Traefik to store its certificates:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;touch&lt;/span&gt; ~/homelab/traefik/acme.json
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;chmod&lt;/span&gt; 600 ~/homelab/traefik/acme.json&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;cloudflared-client-configuration&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#cloudflared-client-configuration&quot;&gt;Cloudflared Client Configuration&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This configures the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;cloudflared&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; Docker container to forward incoming tunnel traffic to Traefik&apos;s HTTPS endpoint.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# ~/homelab/cloudflared/config.yml&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;ingress&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;  # For traffic matching my domain, forward to Traefik&apos;s HTTPS port.&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;  # Traefik will then handle routing based on hostname.&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  - &lt;/span&gt;hostname: &quot;*.mydomain.com&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    service&lt;/span&gt;: https://traefik:443 # &apos;traefik&apos; is the Docker service name for Traefik
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    originRequest&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;      # Traefik&apos;s cert is for *.mydomain.com, not the internal hostname &apos;traefik&apos;.&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;      # noTLSVerify is safe for this internal hop on a trusted Docker network.&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      noTLSVerify&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;  # Default rule for any other traffic hitting the tunnel directly.&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  - &lt;/span&gt;service: http_status:404&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;Rationale for &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;https://traefik:443&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/em&gt;: I faced issues (HTTP status 418) when I tried to route to the Traefik http port. The mentioned approach routes tunnel traffic directly to Traefik&apos;s secure entrypoint. I don&apos;t know if this is the best practice, but it worked for me. The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;noTLSVerify&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; option is necessary because the hostname &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;traefik&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; does not match the certificate&apos;s SAN (Subject Alternative Name). This is acceptable since the traffic is internal and on a trusted Docker network.&lt;/p&gt;
&lt;h1 id=&quot;docker-compose-orchestration&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#docker-compose-orchestration&quot;&gt;Docker Compose Orchestration&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;docker-compose.yml&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file defines and links the Traefik, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;cloudflared&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, and application services.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;version&lt;/span&gt;: &quot;3.8&quot;
 
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;services&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  traefik&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    image&lt;/span&gt;: &quot;traefik:v3&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    container_name&lt;/span&gt;: &quot;traefik_reverse_proxy&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    restart&lt;/span&gt;: unless-stopped
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    security_opt&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;no-new-privileges:true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    env_file&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;.env
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    networks&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;proxy_network
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    ports&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;80:80&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;443:443&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    volumes&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;/var/run/docker.sock:/var/run/docker.sock:ro&quot; # Allows Traefik to discover services
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;./traefik/traefik.yml:/etc/traefik/traefik.yml:ro&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;./traefik/acme.json:/etc/traefik/acme.json&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;./traefik/logs:/var/log/traefik&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    labels&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;      # Configuration for accessing the Traefik dashboard itself&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;traefik.enable=true&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;traefik.http.routers.traefik-dashboard.rule=Host(`dashboard.mydomain.com`)&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;traefik.http.routers.traefik-dashboard.service=api@internal&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;traefik.http.routers.traefik-dashboard.entrypoints=websecure&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;traefik.http.routers.traefik-dashboard.tls.certresolver=cloudflareResolver&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;traefik.http.services.traefik-dashboard.loadbalancer.server.port=8080&quot;
 
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  cloudflared&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    image&lt;/span&gt;: &quot;cloudflare/cloudflared:latest&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    container_name&lt;/span&gt;: &quot;cloudflared_tunnel_client&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    restart&lt;/span&gt;: unless-stopped
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    networks&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;proxy_network
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    env_file&lt;/span&gt;: .env
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    dns&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;1.1.1.1
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;1.0.0.1
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    volumes&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;./cloudflared/config.yml:/etc/cloudflared/config.yml:ro&quot;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    # The command uses the mounted config.yml and the tunnel token.&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    command&lt;/span&gt;: tunnel --no-autoupdate --edge-ip-version auto --config /etc/cloudflared/config.yml run
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    depends_on&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;traefik
 
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  whoami_app&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    image&lt;/span&gt;: &quot;traefik/whoami&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    container_name&lt;/span&gt;: &quot;whoami_service_instance&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    restart&lt;/span&gt;: unless-stopped
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    networks&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;proxy_network
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    labels&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;traefik.enable=true&quot;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;      # Router definition for this application&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;traefik.http.routers.whoami-app-router.rule=Host(`whoami.mydomain.com`)&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;traefik.http.routers.whoami-app-router.entrypoints=websecure&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;traefik.http.routers.whoami-app-router.tls.certresolver=cloudflareResolver&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;traefik.http.routers.whoami-app-router.service=whoami-app-service&quot;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;      # Service definition pointing to the container&apos;s port&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;traefik.http.services.whoami-app-service.loadbalancer.server.port=80&quot; # whoami listens on port 80
 
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;networks&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  proxy_network&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    name&lt;/span&gt;: proxy_network
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    driver&lt;/span&gt;: bridge&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;dns-and-network-adjustments&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#dns-and-network-adjustments&quot;&gt;DNS and Network Adjustments&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;At this point, the local setup is complete. However, we need to tell Cloudflare how to route traffic to our tunnel. When a request comes to the subdomain &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;whoami.mydomain.com&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, it should be directed to the tunnel.&lt;/p&gt;
&lt;h2 id=&quot;cloudflare-public-dns-records&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#cloudflare-public-dns-records&quot;&gt;Cloudflare Public DNS Records&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To add the DNS records for the tunnel, we need to create a CNAME record in Cloudflare&apos;s DNS settings. Following command works great -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;cloudflared&lt;/span&gt; tunnel route dns homelab-main-tunnel whoami.mydomain.com&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This command associates the tunnel with the subdomain &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;whoami.mydomain.com&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. Cloudflare will now route traffic for this domain through the tunnel to my local &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;cloudflared&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; client.&lt;/p&gt;
&lt;h2 id=&quot;local-router-dns-for-split-brain-dns&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#local-router-dns-for-split-brain-dns&quot;&gt;Local Router DNS for Split-Brain DNS&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To ensure that requests from my local network to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;whoami.mydomain.com&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; do not go out to the internet and back in, I set up a split-brain DNS configuration. This allows local devices to resolve the domain directly to my workstation&apos;s local IP address. My router provides this functionality, allowing me to create custom DNS entries for specific domains.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;dashboard.mydomain.com -&gt; 192.168.X.Y (my workstation&apos;s LAN IP)&lt;/span&gt;
&lt;span&gt;whoami.mydomain.com -&gt; 192.168.X.Y&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This ensures local traffic stays within the LAN.&lt;/p&gt;
&lt;h2 id=&quot;cloudflare-ssltls-encryption-mode&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#cloudflare-ssltls-encryption-mode&quot;&gt;Cloudflare SSL/TLS Encryption Mode&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cloudflare provides several SSL/TLS encryption modes. For my setup, I chose the &quot;Full (Strict)&quot; mode. This means that Cloudflare will only connect to my origin server (the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;cloudflared&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; client) if it can establish a secure connection using a valid SSL certificate. This is crucial for ensuring that all traffic between Cloudflare and my local network is encrypted, even if the traffic is not going out to the public internet. I have also noticed that this mode is needed to avoid the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;TOO_MANY_REDIRECTS&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; error.&lt;/p&gt;
&lt;p&gt;In Cloudflare Dashboard -&gt; mydomain.com -&gt; SSL/TLS -&gt; Overview, ensure that the SSL/TLS encryption mode is set to Full (Strict).&lt;/p&gt;
&lt;h1 id=&quot;hiccups-and-solutions&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#hiccups-and-solutions&quot;&gt;Hiccups and Solutions&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&quot;too-many-redirects&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#too-many-redirects&quot;&gt;Too many redirects&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In past, I observed the error &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;ERR_TOO_MANY_REDIRECTS&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; almost always when Cloudflare&apos;s SSL/TLS mode was not set to &quot;Full (Strict)&quot;. This time, apart from configuring this setting, I noticed that my docker subnet was not the standard IP range, so Traefik was not trusting X-Forwarded-Proto from cloudflared. I fixed it by setting &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;forwardedHeaders.trustedIPs&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; on the HTTP entrypoint to allow my docker subnet.&lt;/p&gt;
&lt;h2 id=&quot;418-im-a-teapot&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#418-im-a-teapot&quot;&gt;418 &quot;I&apos;m a teapot&quot;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This was an interesting one. I am not really sure why this happened, but if I didn&apos;t set the traffic forwarding to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;traefik:443&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;cloudflared&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; config, I got this error. I suspect it was because the request was not being routed correctly, and Traefik was returning a default response for unrecognized traffic.&lt;/p&gt;
&lt;h2 id=&quot;404-not-found&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#404-not-found&quot;&gt;404 Not Found&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This error occurred when I tried to access the services without the correct router configuration. I had to ensure that the router for the dashboard was correctly set up in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;docker-compose.yml&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file. Almost always, this was due to a missing or incorrect Traefik label in the service definition.&lt;/p&gt;
&lt;h2 id=&quot;macos-going-to-sleep&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#macos-going-to-sleep&quot;&gt;MacOS going to sleep&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I noticed that my Mac mini would go to sleep after a period of inactivity, causing the tunnel to drop. To prevent this, I set the energy saver settings to &quot;Wake for network access&quot; This ensures that the MacMini is always listening for network connections and the tunnel stays open.&lt;/p&gt;
&lt;p&gt;Though not applicable to my case, another important thing to note is that if you close the lid of your MacBook, it will go to sleep and the tunnel will drop. To prevent this, you can use a tool like Amphetamine or InsomniaX to keep your Mac awake while the lid is closed. Else, you can also keep the MBP plugged in to power and connected to an external display (or a virtual display adapter), which will prevent it from sleeping.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This setup allows me to securely access my homelab services from anywhere while keeping my local network safe. The combination of Cloudflare Tunnels, Traefik, and Docker provides a robust solution for self-hosting applications with HTTPS support. I hope this log helps others in setting up a similar configuration and serves as a reference for my future endeavors.&lt;/p&gt;</content:encoded></item><item><title>Running Adguard with Termux</title><link>https://yashagarwal.in/notes/running-adguard-with-termux/</link><guid isPermaLink="true">https://yashagarwal.in/notes/running-adguard-with-termux/</guid><description>Transform an old Android phone into a powerful homelab server by running Adguard Home and Unbound with Termux for network-wide ad blocking.</description><pubDate>Wed, 25 Dec 2024 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently bought a new phone because after serving me faithfully for six years, my Poco F1&apos;s was left nearly unusable because of my carelessness. I dropped the phone while riding a bike and the screen cracked due to the impact. I had got the screen and battery replaced quite a few times, so I decided to finally say goodbye to this iconic phone.&lt;/p&gt;
&lt;p&gt;For the last two months, the phone was lying unused in my closet. Recently somebody posted their homelab setup using their old phone. This post gave me the idea to bring back my Poco to life. So I started exploring the options available to me. I was planning to buy a Raspberry Pi 5, but the unit economics doesn&apos;t really work in the favour of RPi because of its rising cost. I think this phone can serve as a good alternative of RPi given that the inbuilt battery can also work as a UPS.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/poco-f1.CCnuxVC-_Z14LR10.webp&quot; alt=&quot;The Poco F1&quot; title=&quot;My Poco F1&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4096&quot; height=&quot;3072&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;specs&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#specs&quot;&gt;Specs&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The Poco F1 was a beast of its time. It was launched in 2018 and came with flagship class &lt;a href=&quot;https://www.gsmarena.com/xiaomi_pocophone_f1-9293.php&quot;&gt;specs&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Chipset - Qualcomm SDM845 Snapdragon 845 (10 nm)&lt;/li&gt;
&lt;li&gt;CPU - Octa-core (4x2.8 GHz Kryo 385 Gold &amp;#x26; 4x1.8 GHz Kryo 385 Silver)&lt;/li&gt;
&lt;li&gt;GPU - Adreno 630&lt;/li&gt;
&lt;li&gt;Memory - 64GB 6GB RAM&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I had unlocked it in the first month of purchase and installed and used quite a few custom ROMs on it. It is still a community favorite. Alas, companies don&apos;t manufacture phones like this anymore 😔&lt;/p&gt;
&lt;h1 id=&quot;the-plan&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-plan&quot;&gt;The plan&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;So, given the beefy specs, I was very tempted to set something on it. There were two options available to me -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Installed something like &lt;a href=&quot;https://wiki.postmarketos.org/wiki/Xiaomi_POCO_F1_(xiaomi-beryllium)&quot;&gt;PostMarketOS&lt;/a&gt; or &lt;a href=&quot;https://github.com/mobile-nixos/mobile-nixos/pull/672&quot;&gt;mobile-nixos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Root the phone, install &lt;a href=&quot;https://termux.dev/en/&quot;&gt;Termux&lt;/a&gt; and install all services with it&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There is support for Linux installation on Poco, but I have some essential Google services running on this phone which can&apos;t be substituted. So I abandoned this idea.&lt;/p&gt;
&lt;p&gt;I have previously rooted a number of phones, so rooting this phone was a trivial task. There are a number of tutorials available on the Internet if you are interested.&lt;/p&gt;
&lt;h1 id=&quot;initial-setup&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#initial-setup&quot;&gt;Initial Setup&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Once the phone was rooted, I installed the &lt;a href=&quot;https://github.com/topjohnwu/Magisk&quot;&gt;Magisk&lt;/a&gt; module &lt;a href=&quot;https://github.com/VR-25/acc&quot;&gt;ACC&lt;/a&gt; and configured it to keep my battery levels between 60-75%. As I intended to keep the phone plugged into a charger 24x7, I needed to ensure that the battery is not overburdended. ACC employs certain neat tricks to ensure that battery&apos;s wear and tear is reduced while it is plugged into a charger.&lt;/p&gt;
&lt;p&gt;Now, I wanted to set up Unbound and Adguard on this installation. I started with Adguard as it is easier to setup.&lt;/p&gt;
&lt;h3 id=&quot;adguard-home&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#adguard-home&quot;&gt;Adguard Home&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Adguard Home provides arm64 binaries for arm platforms. This binary works for Android as well. So I downloaded the package from the Github &lt;a href=&quot;https://github.com/AdguardTeam/AdGuardHome/releases&quot;&gt;releases&lt;/a&gt; and unpacked it. Running &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;./AdGuardHome/AdGuardHome&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; under root (use &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pkg install tsu&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;) worked flawlessly. This confirmed that the Adguard works on Android.&lt;/p&gt;
&lt;h3 id=&quot;unbound&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#unbound&quot;&gt;Unbound&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/NLnetLabs/unbound&quot;&gt;Unbound&lt;/a&gt; is available on termux repositories and can be installed easily. But configuring Unbound requires some work. I have prepared the following script to help with the installation, in case you are interested -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;#!/bin/bash&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Update package lists and install required packages&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;pkg&lt;/span&gt; update -y
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;pkg&lt;/span&gt; install -y \
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    unbound&lt;/span&gt; \
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    wget&lt;/span&gt; \
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    openssl-tool&lt;/span&gt; \
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    ca-certificates&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Create necessary directories&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;mkdir&lt;/span&gt; -p $PREFIX/etc/unbound
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;mkdir&lt;/span&gt; -p $PREFIX/var/run/unbound
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Download root hints file&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;wget&lt;/span&gt; https://www.internic.net/domain/named.root -O $PREFIX/etc/unbound/root.hints
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Generate root trust anchor for DNSSEC&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# needs root to read ip_local_port_range file&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;su&lt;/span&gt; -c &quot;/data/data/com.termux/files/usr/bin/unbound-anchor -a \&quot;$PREFIX/etc/unbound/root.key\&quot;&quot;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Create basic configuration file&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;cat&lt;/span&gt; &gt; $PREFIX/etc/unbound/unbound.conf &amp;#x3C;&amp;#x3C; &apos;EOF&apos;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;server:&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    # Basic server settings&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    verbosity: 0&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    interface: 127.0.0.1&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    port: 5335&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    do-ip4: yes&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    do-ip6: no&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    do-udp: yes&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    do-tcp: yes&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    # Access control (adjust according to your network)&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    access-control: 127.0.0.0/8 allow&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    access-control: 192.168.0.0/16 allow&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    # Privacy settings&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    hide-identity: yes&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    hide-version: yes&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    # Memory and performance tuning&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    msg-cache-size: 50m&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    rrset-cache-size: 100m&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    prefetch: yes&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    prefetch-key: yes&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    num-threads: 2&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    # DNSSEC&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    auto-trust-anchor-file: &quot;/data/data/com.termux/files/usr/etc/unbound/root.key&quot;&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    root-hints: &quot;/data/data/com.termux/files/usr/etc/unbound/root.hints&quot;&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;remote-control:&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    control-enable: no&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#032F62&quot;&gt;EOF&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Set correct permissions&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;chmod&lt;/span&gt; 644 $PREFIX/etc/unbound/unbound.conf
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;chmod&lt;/span&gt; 644 $PREFIX/etc/unbound/root.hints
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;chmod&lt;/span&gt; 644 $PREFIX/etc/unbound/root.key
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Test configuration&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;unbound-checkconf&lt;/span&gt; $PREFIX/etc/unbound/unbound.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;start-services-on-boot&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#start-services-on-boot&quot;&gt;Start services on boot&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Currently, the Adguard instance is running in a terminal. As soon as the terminal is killed, the Adguard process will also stop. For a critical DNS service, this is unacceptable. So, we need to run Adguard as a standalone background service. We also need to ensure that if the device is rebooted, the services are autostarted. Termus &lt;a href=&quot;https://f-droid.org/en/packages/com.termux.boot/&quot;&gt;provides&lt;/a&gt; a separate &lt;a href=&quot;https://wiki.termux.com/wiki/Termux:Boot&quot;&gt;Termux:Boot&lt;/a&gt; app to allow running scripts immediately after boot. The &lt;a href=&quot;https://github.com/termux/termux-boot/issues/58#issuecomment-1132533697&quot;&gt;caveat&lt;/a&gt; is that the user needs to unlock the phone and open termux for the Termux:boot to trigger an event which signals Termux to execute the scripts. I couldn&apos;t find a way around this limitation.&lt;/p&gt;
&lt;p&gt;First install the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Termux:Boot&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; apk and open it at least once (as mentioned in the &lt;a href=&quot;https://wiki.termux.com/wiki/Termux:Boot&quot;&gt;docs&lt;/a&gt;). After that you can execute the following script to set up the boot scripts. The script performs the following actions -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a script to start unbound on boot.&lt;/li&gt;
&lt;li&gt;Create a script to start Adguard on boot.&lt;/li&gt;
&lt;li&gt;Check if the services are running and create a log file.&lt;/li&gt;
&lt;/ol&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;#!/bin/bash&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Create directory structure&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;HOME_DIR&lt;/span&gt;=/data/data/com.termux/files/home
 
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;mkdir&lt;/span&gt; -p $HOME_DIR/.termux/boot
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;mkdir&lt;/span&gt; -p $HOME_DIR/.logs
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# 1. Create Unbound startup script (runs first)&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;cat&lt;/span&gt; &gt; $HOME_DIR/.termux/boot/01-unbound.sh &amp;#x3C;&amp;#x3C; &apos;EOF&apos;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;#!/data/data/com.termux/files/usr/bin/bash&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;HOME_DIR=/data/data/com.termux/files/home&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;# Wait for system to fully boot&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;sleep 30&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;# Kill any existing Unbound process&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;su -c &quot;pkill unbound&quot;&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;# Start Unbound with root privileges&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;su -c &quot;/data/data/com.termux/files/usr/bin/unbound -c \&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    /data/data/com.termux/files/usr/etc/unbound/unbound.conf &amp;#x26;&quot;&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;# Log the start&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;echo &quot;$(date): Unbound started&quot; &gt;&gt; $HOME_DIR/.logs/unbound.log&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#032F62&quot;&gt;EOF&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# 2. Create AdGuard startup script (runs second)&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;cat&lt;/span&gt; &gt; $HOME_DIR/.termux/boot/02-adguard.sh &amp;#x3C;&amp;#x3C; &apos;EOF&apos;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;#!/data/data/com.termux/files/usr/bin/bash&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;HOME_DIR=/data/data/com.termux/files/home&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;# Wait for Unbound to initialize&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;sleep 35&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;# Kill any existing AdGuard process&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;su -c &quot;pkill AdGuardHome&quot;&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;# Start AdGuard with root privileges&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;su -c &quot;$HOME_DIR/services/adguard/AdGuardHome \&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    -c $HOME_DIR/services/adguard/AdGuardHome.yaml \&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    -w $HOME_DIR/services/adguard \&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    --no-check-update &amp;#x26;&quot;&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;# Log the start&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;echo &quot;$(date): AdGuard started&quot; &gt;&gt; $HOME_DIR/.logs/adguard.log&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#032F62&quot;&gt;EOF&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# 3. Create status check script (runs last)&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;cat&lt;/span&gt; &gt; $HOME_DIR/.termux/boot/100-check-services.sh &amp;#x3C;&amp;#x3C; &apos;EOF&apos;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;#!/data/data/com.termux/files/usr/bin/bash&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;HOME_DIR=/data/data/com.termux/files/home&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;# Wait for all services to start&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;sleep 45&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;echo &quot;$(date): Checking services status...&quot; &gt;&gt; $HOME_DIR/.logs/status.log&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;check_service() {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    if pgrep $1 &gt; /dev/null; then&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        echo &quot;✓ $1 is running&quot; &gt;&gt; $HOME_DIR/.logs/status.log&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        return 0&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    else&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        echo &quot;✗ $1 is NOT running&quot; &gt;&gt; $HOME_DIR/.logs/status.log&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        return 1&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;    fi&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;}&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;# Check each service&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;check_service unbound&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;check_service AdGuardHome&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;# Show listening ports&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;echo -e &quot;\nListening ports:&quot; &gt;&gt; $HOME_DIR/.logs/status.log&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;su -c &quot;netstat -tupln | grep -E &apos;unbound|AdGuard&apos;&quot; &gt;&gt; $HOME_DIR/.logs/status.log&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#032F62&quot;&gt;EOF&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Make all scripts executable&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;chmod&lt;/span&gt; +x $HOME_DIR/.termux/boot/*.sh&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Test by rebooting your device. Once rebooted, unlock the device and open Termux and wait for 1-2 minutes. Your services should be up and running. Ensure to give forever root access to the Termux app as the services need root access to work.&lt;/p&gt;
&lt;h1 id=&quot;setting-up-adguard&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#setting-up-adguard&quot;&gt;Setting up Adguard&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Once Adguard is up, use &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;ifconfig&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to know the ip of the phone and open &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;&amp;#x3C;ip_address&gt;:3000&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; in another computer on the same subnet. The Adguard UI should show up and you can configure the settings. Below is the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;AdGuardHome.yaml&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; that I used. You can place it in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;$HOME_DIR/services/adguard/AdGuardHome.yaml&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; so that the boot script can use this to initialize your Adguard instance.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;http&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  pprof&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    port&lt;/span&gt;: 6060
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    enabled&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  address&lt;/span&gt;: 0.0.0.0:3000
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  session_ttl&lt;/span&gt;: 720h
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;users&lt;/span&gt;: []
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;auth_attempts&lt;/span&gt;: 5
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;block_auth_min&lt;/span&gt;: 15
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;http_proxy&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;language&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;theme&lt;/span&gt;: auto
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;dns&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  bind_hosts&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    - &lt;/span&gt;0.0.0.0
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  port&lt;/span&gt;: 53
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  anonymize_client_ip&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  ratelimit&lt;/span&gt;: 0
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  ratelimit_subnet_len_ipv4&lt;/span&gt;: 24
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  ratelimit_subnet_len_ipv6&lt;/span&gt;: 56
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  ratelimit_whitelist&lt;/span&gt;: []
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  refuse_any&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  upstream_dns&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    - &lt;/span&gt;127.0.0.1:5335
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  upstream_dns_file&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  bootstrap_dns&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    - &lt;/span&gt;9.9.9.10
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    - &lt;/span&gt;149.112.112.10
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    - &lt;/span&gt;2620:fe::10
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    - &lt;/span&gt;2620:fe::fe:10
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  fallback_dns&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    - &lt;/span&gt;1.1.1.1
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  upstream_mode&lt;/span&gt;: load_balance
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  fastest_timeout&lt;/span&gt;: 1s
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  allowed_clients&lt;/span&gt;: []
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  disallowed_clients&lt;/span&gt;: []
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  blocked_hosts&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    - &lt;/span&gt;version.bind
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    - &lt;/span&gt;id.server
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    - &lt;/span&gt;hostname.bind
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  trusted_proxies&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    - &lt;/span&gt;127.0.0.0/8
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    - &lt;/span&gt;::1/128
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  cache_size&lt;/span&gt;: 0
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  cache_ttl_min&lt;/span&gt;: 0
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  cache_ttl_max&lt;/span&gt;: 0
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  cache_optimistic&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  bogus_nxdomain&lt;/span&gt;: []
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  aaaa_disabled&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  enable_dnssec&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  edns_client_subnet&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    custom_ip&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    enabled&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    use_custom&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  max_goroutines&lt;/span&gt;: 300
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  handle_ddr&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  ipset&lt;/span&gt;: []
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  ipset_file&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  bootstrap_prefer_ipv6&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  upstream_timeout&lt;/span&gt;: 10s
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  private_networks&lt;/span&gt;: []
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  use_private_ptr_resolvers&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  local_ptr_upstreams&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    - &lt;/span&gt;192.168.1.1
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  use_dns64&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  dns64_prefixes&lt;/span&gt;: []
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  serve_http3&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  use_http3_upstreams&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  serve_plain_dns&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  hostsfile_enabled&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;tls&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  enabled&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  server_name&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  force_https&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  port_https&lt;/span&gt;: 443
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  port_dns_over_tls&lt;/span&gt;: 853
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  port_dns_over_quic&lt;/span&gt;: 853
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  port_dnscrypt&lt;/span&gt;: 0
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  dnscrypt_config_file&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  allow_unencrypted_doh&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  certificate_chain&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  private_key&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  certificate_path&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  private_key_path&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  strict_sni_check&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;querylog&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  dir_path&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  ignored&lt;/span&gt;: []
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  interval&lt;/span&gt;: 2160h
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  size_memory&lt;/span&gt;: 1000
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  enabled&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  file_enabled&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;statistics&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  dir_path&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  ignored&lt;/span&gt;: []
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  interval&lt;/span&gt;: 2160h
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  enabled&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;filters&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  - &lt;/span&gt;enabled: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    url&lt;/span&gt;: https://adguardteam.github.io/HostlistsRegistry/assets/filter_1.txt
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    name&lt;/span&gt;: AdGuard DNS filter
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    id&lt;/span&gt;: 1
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  - &lt;/span&gt;enabled: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    url&lt;/span&gt;: https://adguardteam.github.io/HostlistsRegistry/assets/filter_2.txt
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    name&lt;/span&gt;: AdAway Default Blocklist
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    id&lt;/span&gt;: 2
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  - &lt;/span&gt;enabled: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    url&lt;/span&gt;: https://adguardteam.github.io/HostlistsRegistry/assets/filter_51.txt
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    name&lt;/span&gt;: HaGeZi&apos;s Pro++ Blocklist
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    id&lt;/span&gt;: 1735062048
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;whitelist_filters&lt;/span&gt;: []
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;user_rules&lt;/span&gt;: []
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;dhcp&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  enabled&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  interface_name&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  local_domain_name&lt;/span&gt;: lan
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  dhcpv4&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    gateway_ip&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    subnet_mask&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    range_start&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    range_end&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    lease_duration&lt;/span&gt;: 86400
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    icmp_timeout_msec&lt;/span&gt;: 1000
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    options&lt;/span&gt;: []
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  dhcpv6&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    range_start&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    lease_duration&lt;/span&gt;: 86400
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    ra_slaac_only&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    ra_allow_slaac&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;filtering&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  blocking_ipv4&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  blocking_ipv6&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  blocked_services&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    schedule&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;      time_zone&lt;/span&gt;: UTC
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    ids&lt;/span&gt;: []
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  protection_disabled_until&lt;/span&gt;: null
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  safe_search&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    enabled&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    bing&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    duckduckgo&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    ecosia&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    google&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    pixabay&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    yandex&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    youtube&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  blocking_mode&lt;/span&gt;: default
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  parental_block_host&lt;/span&gt;: family-block.dns.adguard.com
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  safebrowsing_block_host&lt;/span&gt;: standard-block.dns.adguard.com
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  rewrites&lt;/span&gt;: []
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  safe_fs_patterns&lt;/span&gt;: []
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  safebrowsing_cache_size&lt;/span&gt;: 1048576
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  safesearch_cache_size&lt;/span&gt;: 1048576
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  parental_cache_size&lt;/span&gt;: 1048576
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  cache_time&lt;/span&gt;: 30
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  filters_update_interval&lt;/span&gt;: 0
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  blocked_response_ttl&lt;/span&gt;: 10
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  filtering_enabled&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  parental_enabled&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  safebrowsing_enabled&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;log&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  enabled&lt;/span&gt;: true
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  file&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  max_backups&lt;/span&gt;: 0
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  max_size&lt;/span&gt;: 100
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  max_age&lt;/span&gt;: 3
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  compress&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  local_time&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  verbose&lt;/span&gt;: false
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;os&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  group&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  user&lt;/span&gt;: &quot;&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  rlimit_nofile&lt;/span&gt;: 0
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;schema_version&lt;/span&gt;: 29&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Please make sure that you modify this configuration according to your network setup. For example, you may want to use your router&apos;s address in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;local_ptr_upstreams&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; field.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/adguard.O1Z6iBY1_VTDFB.webp&quot; alt=&quot;Adguard Dashboard&quot; title=&quot;Adguard Dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2586&quot; height=&quot;1980&quot;&gt;&lt;/p&gt;
&lt;p&gt;That brings us to the end of this post. Please keep sharing it if you find it useful.&lt;/p&gt;</content:encoded></item><item><title>Debug Bluetooth on Linux</title><link>https://yashagarwal.in/notes/debug-bluetooth-on-linux/</link><guid isPermaLink="true">https://yashagarwal.in/notes/debug-bluetooth-on-linux/</guid><description>Troubleshoot and fix common Bluetooth issues on Linux, covering package installation, adapter resets, and wireless card configurations.</description><pubDate>Fri, 17 May 2024 15:55:15 GMT</pubDate><content:encoded>&lt;p&gt;Recently, I installed Debian minimal on my old laptop. The earlier plan was to use this as a server, but I changed my mind and settled on using it as a development server, to avoid storing personal code on my work laptop. The intention was to use it as a headless machine and keep it connected to a monitor and keyboard-mouse pair to interact with it. I was able to connect my monitor to this laptop (after setting up &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;xrandr&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;) but the bluetooth on the machine failed to turn on. This post details various steps I took to root cause and fix the issue.&lt;/p&gt;
&lt;h1 id=&quot;install-the-basic-packages&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#install-the-basic-packages&quot;&gt;Install the basic packages&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;To make bluetooth work on Debian/Ubuntu systems, following packages should be installed -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sudo apt install bluetooth pulseaudio-module-bluetooth blueman bluez-firmware bluez-tools&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now enable the bluetooth service -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sudo systemctl enable bluetooth.service&lt;/span&gt;
&lt;span&gt;sudo systemctl start bluetooth.service&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;You can also enable the kernel bluetooth module using this command -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;modprobe btusb&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now, restart the system (it is optional, but recommended).&lt;/p&gt;
&lt;h1 id=&quot;reset-bluetooth-adapter&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#reset-bluetooth-adapter&quot;&gt;Reset bluetooth adapter&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Use following command to reset bluetooth adapter -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sudo hciconfig hci0 reset&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Scan for bluetooth devices using following command to test the fix -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;bt-adapter -d&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;check-your-wireless-card&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#check-your-wireless-card&quot;&gt;Check your Wireless Card&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;After following the previous steps, the bluetooth should be working. If it doesn’t, the next step is to find any issues with your wireless module. In my case, my laptop has RTL8723BE which in the past has troubled me with many connectivity issues. Recent Linux Kernels are supposed to have a driver for this particular card.&lt;/p&gt;
&lt;p&gt;This card supports two antennas but many manufacturers only put one antenna to save costs. When Linux tries to use both the antennas the failure occurs. The fix is to tell Linux to only use one of the antennas. To do this, run the following commands -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;# Tell kernel to use antenna 1&lt;/span&gt;
&lt;span&gt;echo &quot;options rtl8723be ant_sel=1&quot; &gt;&gt; /etc/modprobe.d/rtl8723be.conf&lt;/span&gt;
 
&lt;span&gt;# remove the existing driver&lt;/span&gt;
&lt;span&gt;sudo modprobe -r rtl8723be&lt;/span&gt;
 
&lt;span&gt;# mount the driver again&lt;/span&gt;
&lt;span&gt;sudo modprobe rtl8723be&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;If this doesn’t improve the wifi signal, try changing &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;ant_sel&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to 2 and try again.&lt;/p&gt;
&lt;p&gt;Another thing that can be done is to disable power management features of this card. This will help if you face frequent disconnections. To disable power management on this card, this &lt;a href=&quot;https://askubuntu.com/a/740599&quot;&gt;StackOverflow post&lt;/a&gt; can be followed.&lt;/p&gt;
&lt;p&gt;This should increase the bluetooth and wifi range of your card which may help in better connections. If the bluetooth still doesn’t work, continue reading.&lt;/p&gt;
&lt;h1 id=&quot;bluetooth-driver-failures&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#bluetooth-driver-failures&quot;&gt;Bluetooth driver failures&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Another thing to observe is the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;dmesg&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; output for any bluetooth related errors. In my case, I saw following errors -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sudo dmesg -w | grep -i blue&lt;/span&gt;
 
&lt;span&gt;[    8.415745] Bluetooth: hci0: rtl: examining hci_ver=06 hci_rev=000b lmp_ver=06 lmp_subver=8723&lt;/span&gt;
&lt;span&gt;[    8.415750] Bluetooth: hci0: rtl: loading rtl_bt/rtl8723b_config.bin&lt;/span&gt;
&lt;span&gt;[    8.422228] bluetooth hci0: Direct firmware load for rtl_bt/rtl8723b_config.bin failed with error -2&lt;/span&gt;
&lt;span&gt;[    8.422238] Bluetooth: hci0: Failed to load rtl_bt/rtl8723b_config.bin&lt;/span&gt;
&lt;span&gt;[    8.422319] Bluetooth: hci0: rtl: loading rtl_bt/rtl8723b_fw.bin&lt;/span&gt;
&lt;span&gt;[    8.461783] Bluetooth: hci0: rom_version status=0 version=1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Searching of this error on the web led me to one Arch Linux forum &lt;a href=&quot;https://bbs.archlinux.org/viewtopic.php?id=219757&quot;&gt;post&lt;/a&gt; which suggested to manually &lt;a href=&quot;https://github.com/lwfinger/rtl8723au_bt/tree/master/Linux_BT_USB_2.11.20140423_8723BE/8723B/rtl8723b_config&quot;&gt;download&lt;/a&gt; the config binary file and put it in the right place. I have used artefacts from the &lt;a href=&quot;https://github.com/lwfinger&quot;&gt;lwfinger&lt;/a&gt; before, so I decided to trust this. But it is not usually recommended to download random files from the Internet and execute them. After downloading the file, I executed following command -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sudo cp rtl8723b_config /usr/lib/firmware/rtl_bt/rtl8723b_config.bin&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Reboot the system afterwards.&lt;/p&gt;
&lt;h1 id=&quot;rfkill&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#rfkill&quot;&gt;Rfkill&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;However, this also didn’t work. Rfkill is a Linux utility used to manage wireless devices. Sometimes, a bluetooth device can be soft-blocked by &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;rfkill&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. In that case, you will have to enable it before the bluetooth can be used.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;yash@homelab ~&gt; rfkill list&lt;/span&gt;
&lt;span&gt;0: phy0: Wireless LAN&lt;/span&gt;
&lt;span&gt;	Soft blocked: no&lt;/span&gt;
&lt;span&gt;	Hard blocked: no&lt;/span&gt;
&lt;span&gt;1: hci0: Bluetooth&lt;/span&gt;
&lt;span&gt;	Soft blocked: yes&lt;/span&gt;
&lt;span&gt;	Hard blocked: no&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;If any of your devices are soft-blocked, run the following command to unblock it -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;rfkill unblock bluetooth&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;After this step, again check if the bluetooth can be enabled. In my case, even after this step, the bluetooth didn’t work, so I debugged further.&lt;/p&gt;
&lt;h1 id=&quot;udev&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#udev&quot;&gt;Udev&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;After a long debugging session, I discovered the following &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;udev&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; rule in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/udev/rules.d/&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;## DISABLE BLUETOOTH&lt;/span&gt;
&lt;span&gt;SUBSYSTEM==&quot;rfkill&quot;, ATTR{type}==&quot;bluetooth&quot;, ATTR{state}=&quot;0&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;I may have added this rule when I was trying to configure my system as a headless home server. Having this rule on a fresh system is highly unlikely, so you may not have to worry about this.&lt;/p&gt;
&lt;p&gt;I removed this rule and rebooted the system.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Finally, after almost two hours of debugging, the bluetooth on my laptop was finally working. It is a story for another day that I didn’t use the bluetooth for even for 10 minutes after this.&lt;/p&gt;
&lt;p&gt;Do leave a comment if you find this post helpful.&lt;/p&gt;</content:encoded></item><item><title>Train the algorithm</title><link>https://yashagarwal.in/notes/train-the-algorithm/</link><guid isPermaLink="true">https://yashagarwal.in/notes/train-the-algorithm/</guid><description>Battling social media addiction? Explore my journey of digital detoxification, understanding usage patterns and reclaiming control from algorithms.</description><pubDate>Sun, 12 May 2024 06:40:24 GMT</pubDate><content:encoded>&lt;p&gt;It is Sunday today so I decided to take a break from my screen-heavy routine. It rained yesterday night so the morning felt a lot cooler than the scorching heat I am used to in the month of May. The early morning breeze tempted me to go for a morning walk. Walks can be a great way to spend some time with yourself and contemplate on your life. I also could’ve this opportunity to have some time doing self-review. But I completely wasted this chance and spent most of my time staring at my smartphone and scrolling X (formerly Twitter).&lt;/p&gt;
&lt;p&gt;I vividly remember another such &lt;a href=&quot;https://yashagarwal.in/notes/deactivated-my-facebook-account&quot;&gt;incident&lt;/a&gt; that happened during the last year of college. It was March and I had just spent first few hours of my day scrolling through Facebook (it was still famous those days). An introspection on that incident prompted me to leave Facebook forever. I took several steps after that day to control my urge to use Facebook and it mostly worked. The decreasing popularity of Facebook among my generation definitely aligned perfectly with the task at hand and I was able to get rid of Facebook from my life.&lt;/p&gt;
&lt;p&gt;Now, after almost six years, I have been battling yet another bout of social media addiction for last few months. Nowadays, I use primarily four social media apps - X, Instagram, Quora and WhatsApp. Below, I detail my usage patterns for these four apps and how I try to use these in a controlled manner.&lt;/p&gt;
&lt;p&gt;Quora is the easiest one. Their content moderation policies and the subsequent boycott by prominent writers meant that the quality of the content available on the platform has greatly reduced. I benefitted the most from this. Now, I tend to open Quora once or twice a month at max.&lt;/p&gt;
&lt;p&gt;WhatsApp is almost unavoidable for me. I have worked slowly over the years to reduce my usage of the app, to the disappointment of some people in my life. I rarely send messages to anyone and even rare is to get a message from someone. Now, if I receive a message, I am almost certain that the sender is in some emergency. WhatsApp’s recent changes (regarding business chats) has definitely increased daily notifications on my phone. Its unsubscribe functionality is mostly broken (looking at you, HDFC) so, I am not able to block some businesses. But I guess that is a nuance that I can live with, for now.&lt;/p&gt;
&lt;p&gt;I started using Instagram more seriously during my &lt;a href=&quot;https://yashagarwal.in/notes/i-got-engaged&quot;&gt;courtship&lt;/a&gt; period, partly because my fiancée (now wife) was only active on Instagram. At that time, I was instantly glued to the Instagram’s reels functionality. It worked really well, showed me engaging reels. It &lt;em&gt;somehow&lt;/em&gt; knew all my interests. I was spending 4-5 hours everyday just scrolling (or shall I say swiping?) through the reels. It even allowed me to save the reels for future, though saving reels mostly catered to my FOMO. Most of the saved reels remain untouched to this day. My usage of Instagram reached such a point that I started to experience several psychological and behavioural issues. I felt myself battling self-doubt, loathing and imposter syndrome. Seeing others’ artificial progress made me jealous. It gave me anxiety. The more I swiped, the less confident I felt about myself. The constant pressure to keep up with the latest trends made me scared and less aware about myself. The &lt;em&gt;compulsion&lt;/em&gt; to announce to the world; birthdays, anniversaries and what not, the urge to upload that one photo out of the thousands, just to show the world that I am doing great in life. I am done with this manipulation, I am done with letting an algorithm control me. I am trying to eliminate Instagram from my daily life for a while now. Doing it suddenly would have probably resulted in Withdrawal Syndrome. So I decided to approach this issue in a stepwise manner. First step was to uninstall the Instagram app from my phone. I slowly forced myself to use the web version of Instagram. While the web version is functional, there are some hiccups here and there - stories take time to load, no doom-scrolling etc. These minor details definitely helped me to feel the irritation. Once the irritation kicked in, it was easy to stop using the web version also. Ultimately, I decided to take the final step of deactivation. It has been three days since I deactivated my account. I haven’t felt the urge to open the app even once. These are still early days and I need to keep a close eye on my behavioural patterns to avoid falling into the trap again.&lt;/p&gt;
&lt;p&gt;My current go-to social media platform is X. X can be quite toxic if one is interested in certain topics - like politics. I tend to avoid these topics mostly. I use X primarily to gain knowledge about Tech, Indie-hacking, SaaS businesses and other similar topics. However, I am well aware about the potential pitfalls of using it more often so I consciously try to put limits on my usage of the web app as much as possible. Doom-scrolling is a definite no-no.&lt;/p&gt;
&lt;p&gt;Having said this, I am not fully capable of cutting myself completely from the social media. We live in a world which is increasingly being controlled by &lt;em&gt;the algorithm&lt;/em&gt;. The algorithm is constantly watching us, waiting to identify patterns in our behaviour. These algorithms are designed by some of the smartest people in the world who have spent years studying the human brain. It is difficult to beat them at their game.&lt;/p&gt;
&lt;p&gt;In my opinion, it is okay to fall pray to the social media sometimes. But it is important to understand what you want and what you don’t. Tell the algorithm more of what you want. Spend some time understanding your interests and what values they bring. I find politics interesting, but it doesn’t add any real value to my skill set, so I try to not consume any political content on social media. Conversely, I work in tech, and I intend to get into solopreneurship, so I follow people doing great in these areas. Ruthlessly unfollow people who are posting frivolous content or content outside of your interest areas. Do this consistently and the algorithm will bend to your will.&lt;/p&gt;
&lt;p&gt;If you are passionate about your goals and if you are willing to bite the bullet, nothing can distract you, not even the best algorithms in the world.&lt;/p&gt;</content:encoded></item><item><title>Homelab: The experiment begins</title><link>https://yashagarwal.in/notes/homelab-experiment-begins/</link><guid isPermaLink="true">https://yashagarwal.in/notes/homelab-experiment-begins/</guid><description>Embark on a long-awaited homelab journey, transforming an old laptop into a powerful server. Explore Linux, Docker, and infrastructure skills.</description><pubDate>Tue, 27 Feb 2024 08:55:15 GMT</pubDate><content:encoded>&lt;h1 id=&quot;background&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#background&quot;&gt;Background&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I have been planning to set up a homelab for almost six years now. It all started in the last year of my graduation. At that time, the goal was to learn about PC hardware by building a high-end PC. On the other hand, I was already familiar with enterprise level hardware because of my involvement in the &lt;a href=&quot;https://athena.nitc.ac.in/&quot;&gt;SSL&lt;/a&gt; lab upgradation effort (pity I didn’t get to feel that shiny new server I recommended as the next upgrade for the lab), so I also ventured into setting up a proper server but that was always a distant dream considering the cost to acquire a server and power it.&lt;/p&gt;
&lt;p&gt;Later I started looking at Raspberry Pi. My earliest memory of the Raspberry Pi is from 2019 when I was working with Cisco in Bangalore. I did extensive research, prepared a plan but somehow ended up never buying the SBC. A Raspberry Pi is not sufficient alone in most cases - you need a case, an active cooler, cables, power supply, and a UPS. One buys all of this and suddenly the Raspberry Pi starts to look rather unattractive. I couldn&apos;t convince myself about the unit economics of buying the Raspberry Pi, so I dropped this plan.&lt;/p&gt;
&lt;h1 id=&quot;why-now&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#why-now&quot;&gt;Why now?&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;For the last 4-5 months, &lt;em&gt;since I have decided to focus on my career again&lt;/em&gt;, I have been thinking about exploring the Linux world again. Naturally, the Raspberry Pi came back on my radar. I am going to work from home for the foreseeable future. More importantly, I have a mostly uninterruptible internet connection. The power connection sometimes fluctuates in my area. A RPi would instantly go down in case of a power cut, along with a high probability of data corruption. I was able to circumvent the issue of the router going down on a power cut by buying a &lt;a href=&quot;https://cuzorlabs.com/products/router-ups-for-12v2a&quot;&gt;router UPS&lt;/a&gt;, but buying one for RPi didn&apos;t make sense to me.&lt;/p&gt;
&lt;p&gt;Being a backend developer, although the sysadmin, devops, networking, and platform skills don&apos;t bring any apparent advantages to my day-to-day work, I have decided to invest some time in home-labbing because -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It has been my passion for a long time and I want to finally experience it.&lt;/li&gt;
&lt;li&gt;A peripheral knowledge of the infra and platform side of things definitely make it easier to design more efficient systems and debug non-trivial issues.&lt;/li&gt;
&lt;li&gt;As I progress in my career, I will not be handling just one portion of the product. I intend to take more and more responsibilities. That means wearing more than one hat. A homelab provides me an opportunity to learn one such skill.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;the-hardware&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-hardware&quot;&gt;The Hardware&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I bought a &lt;strong&gt;&lt;a href=&quot;https://support.hp.com/us-en/document/c05030912&quot;&gt;HP Pavilion Notebook - 15-ab516tx&lt;/a&gt;&lt;/strong&gt; in the third year of my graduation. At that time, it was a pretty powerful laptop and served me well in all my Linux and Windows experiments throughout the college term.&lt;/p&gt;
&lt;p&gt;It has been gathering dust in my closet since I started using MacOS and Apple hardware. Getting back to Windows and its keyboard layout has proven to be more difficult than I anticipated. So, my use of this laptop was limited to occasionally using Windows and as an offsite backup destination for some of my old data (that I am keeping only for nostalgia, huh). I was hesitant to keep it powered on 24/7 to preserve it for some more years. But then I convinced myself that in the worst case scenario, I will have to buy a new battery. Apart from that, the possibility of it getting fried is pretty miniscule.&lt;/p&gt;
&lt;p&gt;It has an Intel Core-i5 6th generation CPU with four cores. It currently has 8 GB DDR3L-1600 SDRAM installed. The other RAM slot is a DDR type slot, but I am not sure if this is accurate. For now, I assume that I am limited to 8GB of RAM on this system. The ethernet port on this device is the Integrated 10/100 BASE-T Ethernet LAN.&lt;/p&gt;
&lt;p&gt;Yet another under-utilised component on this device is the NVIDIA 940M (2 GB DDR3 dedicated). I intend to use it for video transcoding in future however, I am doubtful about the support for it. If this doesn’t work, I might have to settle for Intel’s inbuilt graphic card.&lt;/p&gt;
&lt;p&gt;It came with a 1TB 5400 rpm SATA HDD. It got very slow with time, so I purchased a 512 GB SSD and placed it in the SATA slot of my HDD. Later I removed the disk tray from the laptop and installed the unused HDD into its SATA port using a caddy. So, now I have 1.5 TB of storage space. Windows 10 is installed on a 200 GB NTFS partition. Another 500 GB is occupied with my personal files (which I intend to organise later).&lt;/p&gt;
&lt;h1 id=&quot;the-os&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-os&quot;&gt;The OS&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I have not tinkered with Linux for almost 6 years now. Since I left college, somehow my zeal to explore new stuff also diminished. I had developed a false impression that building something is more important than using what others built. While I still believe in it, I don’t want to restrict myself with such black and white statements. Both activities have their significance. What matters more is to keep the fire burning.&lt;/p&gt;
&lt;p&gt;Anyway, I had a couple of choices for the OS on my server - Ubuntu server, Arch Linux, Debian minimal, and a few Virtualisation platforms - Proxmox etc. Proxmox was out of the question because I wasn’t sure that my laptop would be able to spin up more than a few VMs with just 4 cores and 8 GB of RAM.&lt;/p&gt;
&lt;p&gt;I don’t have a good experience with Ubuntu in the past, even though it has good support for non-free drivers, especially NVIDIA. Arch Linux may have been a good choice but I wanted to stick with an apt-based distro. In the end, I decided to install &lt;a href=&quot;https://www.debian.org/CD/netinst/&quot;&gt;Debian-minimal&lt;/a&gt; on a 100 GB dedicated root partition.&lt;/p&gt;
&lt;p&gt;For some reason (most likely due to my RTL8723BE wireless card on my laptop), the installer failed a couple of times due to OOM issues. I had to boot up the installer by modifying the GRUB by adding following lines (although I doubt &lt;a href=&quot;https://askubuntu.com/questions/1190813/realtek-rtl8723be-pcie-wireless-network-adapter-is-crashing-my-ubuntu-18-04&quot;&gt;PCIE errors&lt;/a&gt; can cause OOM, but it worked, so all good) -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/span&gt;=&quot;quiet pci=noaer&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Once the installation finished, I was greeted with the default TTY screen.&lt;/p&gt;
&lt;h1 id=&quot;whats-next&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#whats-next&quot;&gt;What’s next&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The Debian minimal comes with literally nothing. Not even &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. In the next post in this series, I plan to write about setting up the Debian server - networking, SSH, setting up lid-close action etc. Later I will explain how to set up Docker MacVLAN interfaces and make docker containers appear like another device on your network.&lt;/p&gt;
&lt;p&gt;As with all other things, it is easy to get lost in many options available for homelab. So I have decided a few minimum required goals that I would like to achieve with this exercise -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a fully-reproducible setup.
&lt;ol&gt;
&lt;li&gt;Host a few of the interesting services - bookmark manager, Plex, Adguard, reverse proxy etc.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Allow outside world access to some of the services and secure the server.&lt;/li&gt;
&lt;li&gt;Learn VPNs and configure one.&lt;/li&gt;
&lt;li&gt;Document the progress and the concepts learned.&lt;/li&gt;
&lt;li&gt;Few of the technologies I plan to learn -
&lt;ol&gt;
&lt;li&gt;Docker - I already have a good experience with it, so it would be a refresh for me.&lt;/li&gt;
&lt;li&gt;Ansible - Automate the repetitive work&lt;/li&gt;
&lt;li&gt;Wireguard - I think it would be a good experience to learn how it works behind the scenes. Also explore TailScale later.&lt;/li&gt;
&lt;li&gt;DNS, Port Forwarding, CGNAT, IPv6, reverse proxy, cert management etc - to allow outside world access.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While this is an exciting thing to dive into, I will also be focusing on employing my server for development work. I have planned many exciting things for 2024, most of which will get some mention on this blog.&lt;/p&gt;
&lt;p&gt;Stay tuned!&lt;/p&gt;</content:encoded></item><item><title>Thailand: Sandy Beaches to Bustling Streets</title><link>https://yashagarwal.in/notes/thailand-sandy-beaches-to-bustling-streets/</link><guid isPermaLink="true">https://yashagarwal.in/notes/thailand-sandy-beaches-to-bustling-streets/</guid><description>Discover the magic of Thailand, from serene beaches to bustling streets. This travelogue shares practical tips on planning, money exchange, and visa processes.</description><pubDate>Sat, 19 Aug 2023 03:52:15 GMT</pubDate><content:encoded>&lt;h1 id=&quot;introduction&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Since COVID began, I have been at home, thoroughly immersed in work and routine life. I was never really an enthusiastic traveller, much less when nobody pushed me. I went on a few trips during college (mainly because of FOMO) and two visits to Coorg and &lt;a href=&quot;https://yashagarwal.in/notes/travelogue-chikmagalur&quot;&gt;Chikmagalur&lt;/a&gt; while in Bangalore. Laziness, finance and my tendency to stay clear of risks led to the state where I kept desiring to travel without concrete action.&lt;/p&gt;
&lt;p&gt;Keeping this behaviour in sight, I always desired a partner who thinks differently from me when it comes to travelling. And God just listened to me. My spouse is a travel enthusiast (perhaps because she hasn&apos;t travelled much till now). So when she nudged me to go on a trip somewhere, I decided to break my bubble and take on the adventure.&lt;/p&gt;
&lt;p&gt;I have never been to any place outside of India. So, a foreign trip was definitely on my mind for a long time. When planning, we considered many options - Bali, Sri Lanka, Bhutan, Malaysia, Thailand, and Singapore — all countries nearby to India.&lt;/p&gt;
&lt;p&gt;At last, we settled on Thailand, partly because the flight tickets were the cheapest at the time of booking for Thailand. Another destination top on my list was Bali, Indonesia. However, the lack of a direct flight from Jaipur/Delhi to Bali meant that I had to spend some extra time on the flight (along with increased flight costs), so we decided to go with Thailand.&lt;/p&gt;
&lt;p&gt;We had planned to visit Thailand for our honeymoon in January 2023, but we had to reschedule the trip due to unforeseen circumstances. We decided to reschedule it for June, which, although a low season in Thailand, has humid yet decent weather for roaming around. Meanwhile, we went to &lt;a href=&quot;https://yashagarwal.in/notes/manali-mountains-and-memories&quot;&gt;Manali&lt;/a&gt; for a short honeymoon trip.&lt;/p&gt;
&lt;h1 id=&quot;money-exchange&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#money-exchange&quot;&gt;Money Exchange&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I did some research on popular payment methods in Thailand. For one thing, cash is still king there, at least for a tourist. Many shops accept QR code-based payments, and a few also accept cards. VISA and MasterCard rule in card space. The acceptability of Diners Club is pretty much limited to Airport lounges. My HDFC Diners Black Card was turned down everywhere I tried.&lt;/p&gt;
&lt;p&gt;Anticipating this situation, I had already kept enough Thai Baht for day-to-day expenses. I got an exchange rate of 0.4 baht per rupee in Jaipur. In Phuket and Bangkok, I saw a few exchanges offering rates of 0.42 baht. Don&apos;t exchange your money at airports; instead, carry at least ฿4400 for Visa-on-arrival fees and a few hundred bahts to pay for transportation from the airport to your hotel.&lt;/p&gt;
&lt;h1 id=&quot;air-travel&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#air-travel&quot;&gt;Air Travel&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I last boarded an aeroplane in March 2020 when I returned to Jaipur from Bangalore, seeing the signs of imminent lockdown. After that, I didn&apos;t get any chance to board a flight. So I was very excited about air travel again. Alas, my passport also got an opportunity to be useful to me after sitting idly for so long.&lt;/p&gt;
&lt;p&gt;During this trip, I got to visit three airports - Jaipur Airport (JAI), Don Mueang International Airport (DMK) and Phuket International Airport (HKT).&lt;/p&gt;
&lt;p&gt;The plan was to fully utilise Diners Black&apos;s unlimited international lounge accesses. However, due to hiccups by HDFC, the add-on card for my wife didn&apos;t arrive on time, so we had to settle with one Diners Black with unlimited lounge accesses and one DreamFolks card with only two lounge accesses. We decided to utilise only the two lounge accesses available to us. Both of these visits were at the DMK airport - one in the Coral Executive Lounge in the domestic terminal and the other in the Miracle Lounge in the international terminal. I was unsure if they would allow my wife as both cards had my name, but they decided to show two separate visits for me. Makes sense, as the cards were different.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/the-coral-executive-lounge.IR0Ajd7n_Z1pGEgm.webp&quot; alt=&quot;The Coral Executive Lounge&quot; title=&quot;The Coral Executive Lounge&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4032&quot; height=&quot;3024&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;visa-on-arrival&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#visa-on-arrival&quot;&gt;Visa on Arrival&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Thailand provides visas on arrival for Indian tourists. We reached DMK early morning at 5 AM. As we had a subsequent (but not connecting) flight to Phuket at 10 AM, we were confused about whether to take the Visa first or go to immigration first. Later we figured it out. If we had a connecting flight, we could have approached immigration and claimed our baggage first before getting a Visa at the final destination airport. But as our flight was not connecting, we had to get the Visa first. There was a long queue for Visa-on-arrival. It took us a good 1 hour to get our passports stamped. The fee is supposed to be ฿2000, but they took ฿2200 per person from us. The process is simple. You fill out a form and stand in a queue. When your turn comes, provide all your documents (including flight tickets, hotel bookings etc.), pay the fees and give your passport to them. After some time, they will come back outside with batches of stamped passports.&lt;/p&gt;
&lt;p&gt;After getting our Visa, we proceeded to the immigration counter. Here also, the process was smooth. They took our fingerprints and photo and put an entry stamp on our passports. After this we claimed our baggage and waited for 2 hours to board our next flight.&lt;/p&gt;
&lt;h1 id=&quot;sim-card&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#sim-card&quot;&gt;Sim Card&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Another thing that we researched was whether to use an Indian sim with international roaming activated or buy a local sim. International roaming packs of Indian telecom operators are quite expensive, so it was economical to buy the local sim.&lt;/p&gt;
&lt;p&gt;I read on the Internet that the sim providers at airports sell sim for a premium, so it is better to buy from the city. My experience is different. We didn&apos;t buy the AIS sim at the airport and waited to reach Phuket city. Inside the city, we didn&apos;t find any vendor selling AIS sim. Everybody was selling dTac sims. The pricing was the same everywhere, ฿299, but the benefits provided were different. At last, we decided to settle on a travel sim by dTac, which needed no documents and provided 50 minutes of calling and (not truly) unlimited internet for 7 days. This was more than sufficient for our daily needs.&lt;/p&gt;
&lt;h1 id=&quot;phuket&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#phuket&quot;&gt;Phuket&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Several transport options are available at the Phuket airport to reach your hotel. The private taxi costs ฿800 for the Patong area, and a shared minibus costs ฿180 per person. We opted for the minibus because it was economical and didn&apos;t compromise on comfort either. Around ten people can sit in a minibus, and the driver drops you at the hotel.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/phuket-airport.ZknuA6BH_kzPoE.webp&quot; alt=&quot;Phuket Airport&quot; title=&quot;Phuket Airport&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4032&quot; height=&quot;3024&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;day-1&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#day-1&quot;&gt;Day 1&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We reached our hotel, The Silver Resortel, at around 2 PM. I booked this hotel mainly because of the excellent reviews on &lt;a href=&quot;https://booking.com/&quot;&gt;booking.com&lt;/a&gt; and its proximity to Patong Beach and Bangla Road. The hotel was equipped with all the necessary amenities and facilities. Like many other hotels in Phuket, they asked for a security deposit of ฿500 which was refunded at checkout.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/the-silver-resortel-hotel.Bm1tCMuv_pO5q2.webp&quot; alt=&quot;The Silver Resortel Hotel&quot; title=&quot;The Silver Resortel Hotel&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;It has been 5 years since I stepped into a beach town. So, the first thing I did after a quick nap was to run towards the beach. We forgot to take the free beach towels from the hotel, so I had to sit in the sand. In a way, it was a good thing. The sea was rough in Phuket as it is the rainy season there. It was first beach visit for my wife, so she was equally excited. We sat on the beach for 2 hours, played in the pristine, chilled water and thoroughly enjoyed the sunset.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/the-patong-beach.BaUyrwch_WlllH.webp&quot; alt=&quot;The Patong Beach&quot; title=&quot;The Patong Beach&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4032&quot; height=&quot;3024&quot;&gt;&lt;/p&gt;
&lt;p&gt;After coming from the beach, we decided to search the area for a good Indian Vegetarian Restaurant. While roaming around, we reached the famous Bangla Road, the party point of Phuket. And boy, what a spectacular scene this was! People were wandering around freely. Bargirls and ladyboys wearing skinny clothes try to lure customers into the clubs. Open clubs playing music, customers having &quot;deep&quot; conversations while sipping beer, a lot of vendors selling every kind of stuff and people performing on the road. Being in such an environment was a new experience, but I did not feel intimidated or threatened by anyone.&lt;/p&gt;
&lt;p&gt;In our search for food, we reached &lt;a href=&quot;https://goo.gl/maps/BVMQNngyLdg3VixK7&quot;&gt;Amritsr Restaurant&lt;/a&gt; and ordered Kulchas. We weren&apos;t expecting good taste, but we were surprised. The food was tasty, though somewhat bland. The waiters and manager treated us nicely, and we left with a good impression. Throughout my trip, I did one thing wrong - converting Thai Bahts to INR every time I decided to make a purchase. Comparing the prices in Thailand to their exchange rate pricing in India was incorrect. This made me conscious as I found everything expensive compared to India. We spent ฿180 at Amritsr, which seemed very expensive for a Kulcha. But we were to get more surprises in days to come.&lt;/p&gt;
&lt;p&gt;While planning for the next day, we were confused about tours to Phi Phi Island or James Bond Island. After watching some Youtube videos, we decided to visit Phi Phi Islands this time and leave James Bond Islands for another trip. While travelling back to the hotel from Amritsr restaurant, we stopped at a few tour agents and queried about the tour plans. The thing with these tour operators is that they quote exorbitant prices. It is always advisable to bargain and try to bring the costs down.&lt;/p&gt;
&lt;p&gt;The first agent gave us a quote of ฿3600 for a two-person trip. After haggling with her, she pretended to talk to her boss and agreed to ฿3000. We were unsatisfied with this price, so we decided to try elsewhere. The last agent we tried finally gave us a price of ฿2500 for two people. On talking to him about Phuket City Tour, he agreed to a total cost of ฿4600 for two persons. So that was what we could bargain. ฿1250 per person for Phi Phi Island Tour and ฿1100 per person for the City tour. We tried to negotiate a bit more, but the agent did not relent, so we decided not to pursue further.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/phi-phi-island-tour-brochure.CpzA3pHt_Z1JqThU.webp&quot; alt=&quot;Phi Phi Island Tour Brochure&quot; title=&quot;Phi Phi Island Tour Brochure&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4000&quot; height=&quot;2509&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;day-2&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#day-2&quot;&gt;Day 2&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The next day started early. The tour started at 7.30 in the morning. The minibus picked us up from the hotel, and we were transferred to the eastern coast of Phuket, where we were provided breakfast. As vegetarians, we had to satisfy ourselves with fruits.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/the-boat-boarding-point.BWgQGrYx_Z1qzVwy.webp&quot; alt=&quot;The boat boarding point&quot; title=&quot;The boat boarding point&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;After breakfast, we boarded the speed boat along with 30-35 people. This was my first sea ride, so I was quite excited about it. We visited 4-5 islands throughout the day and stayed on the boat for over 5 hours. We had lunch on Phi Phi Island, a fully commercialised island with many resorts and restaurants.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/lunch-at-phi-phi-island.BYpmHi5a_Z2iL5DC.webp&quot; alt=&quot;Lunch at Phi Phi Island&quot; title=&quot;Lunch at Phi Phi Island&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;Our tour also included Snorkelling, but we weren&apos;t confident about it, so we decided not to do it. I am definitely going to try it someday in future, though.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/maya-bay-beach.DtjgiU_W_Z2eaLAz.webp&quot; alt=&quot;Maya Bay Beach&quot; title=&quot;Maya Bay Beach&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4032&quot; height=&quot;3024&quot;&gt;&lt;/p&gt;
&lt;p&gt;After a gruelling day at sea, we came back to our base at around 6 PM. From there, it took another 1 hour to reach our hotel in the Patong area.&lt;/p&gt;
&lt;p&gt;For Dinner, we decided to visit &lt;a href=&quot;https://goo.gl/maps/fsNBw3PTQVbSXL1j9&quot;&gt;Hare Krishna Vegetarian Indian Restaurant&lt;/a&gt;. This was one of the most economical yet satisfying restaurants we tried on this trip. The food was good, the hospitality was great, and the bill was pocket-friendly.&lt;/p&gt;
&lt;p&gt;On our way back to the hotel at night, we decided to go back to the tour agent from whom we took the Phi Phi Island tour and booked the Phuket City tour package for ฿2100 for two pax.&lt;/p&gt;
&lt;h2 id=&quot;day-3&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#day-3&quot;&gt;Day 3&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The city tour was scheduled from 10 AM to 4 PM with no lunch included. We visited Tiger Park, Big Buddha, Chalong Temple, a Cashew Nut factory, a Honey farm and Elephant trekking.&lt;/p&gt;
&lt;p&gt;The Tiger Park has many tigers ranging from big, medium and small sizes, which are domesticated in such a way that you can go near them, touch them and pat them. I don&apos;t know if they were drugged, but I didn&apos;t feel good seeing them. I didn&apos;t see any visible signs of brutality there, so I don&apos;t know if it is just the result of their upbringing in human vicinity or the effect of any drug.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/so-near-yet-so-relaxed.DSYs4PsD_Z12tr1j.webp&quot; alt=&quot;So near yet so relaxed&quot; title=&quot;So near yet so relaxed&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;Big Buddha has a very large idol of Buddha and a small temple dedicated to Buddha. It has some good scenes. Apart from that, I don&apos;t see any significant value in this place.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/big-buddha.BeP3H2x3_Z23iWJ6.webp&quot; alt=&quot;Big Buddha&quot; title=&quot;Big Buddha&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;The next stop was the Chalong Temple. This is another one of several Buddhist temples we visited on this trip. There are many temples in this complex, all of which were alien to us. So we did what a Dharmic believer would: bow and pray to the idol.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/the-chalong-temple.Cnw39dOC_ZaiiSS.webp&quot; alt=&quot;The Chalong Temple&quot; title=&quot;The Chalong Temple&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;After this, we went to a Cashew Nut factory and Honey Farm. It was likely the collaboration of our tour operator with these two enterprises to help increase their sales to foreign tourists. The products were of good quality and unique because you probably won&apos;t find similar things anywhere else.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/honey-farm.DjOHyGdy_1PhBAO.webp&quot; alt=&quot;Honey Farm&quot; title=&quot;Honey Farm&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;After these, we went to the last stop - Elephant Trekking at Nopparat Elephant Camp. I regret going there. I could clearly see overworked elephants and their mahouts using a sharp objects to pierce them and keep them on track. However, at that time, I enjoyed the experience of sitting on an elephant. The mahout even allowed me to freely sit in his place and ride the elephant. This was risky and could have resulted in an accident, but nothing wrong happened. I would not support them by going there again. But the other side of this story is that this money is the only way the elephants could survive while being in captivity.&lt;/p&gt;
&lt;p&gt;This marked the end of our city tour. We were dropped off at our hotel by the tour operator. After taking some rest, we decided to head to the beach to enjoy the vastness of the ocean for one last time for a while.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/she-clicks-lovely-photos.Cj36rFPL_Z1MMJym.webp&quot; alt=&quot;She clicks lovely photos&quot; title=&quot;She clicks lovely photos&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/i-am-no-less.B0p0pL2A_12h6A1.webp&quot; alt=&quot;I am no less!&quot; title=&quot;I am no less!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;After returning from the beach, we decided to go to another vegetarian restaurant - &lt;a href=&quot;https://goo.gl/maps/Ky7iTiCWTLHr8Q178&quot;&gt;Kailash Parbat&lt;/a&gt;. We found it to be okayish despite its high ratings on Google.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/the-bangla-road.CSweUYIJ_2594Jk.webp&quot; alt=&quot;The Bangla Road&quot; title=&quot;The Bangla Road&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;After dinner, we booked our minibus to Phuket airport, which cost us ฿200 per pax. We had to board our minibus early the following day; we decided to bid farewell to Phuket and left for the hotel after roaming around Bangla Road for an hour.&lt;/p&gt;
&lt;p&gt;I found Phuket to be a friendly and safe city to roam around. We missed visiting many things - the most prominent being Phuket Town. However, we thoroughly enjoyed whatever we could see. The local people we interacted with were humble and behaved patiently and calmly with us. Being a tourist city, people will try to coax you, so one needs to be alert constantly; overall, the people appeared friendly.&lt;/p&gt;
&lt;h1 id=&quot;bangkok&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#bangkok&quot;&gt;Bangkok&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Before I start describing the trip, let me spend a moment praising Bangkok. I have not travelled extensively, so my experience is limited. I haven&apos;t seen any city more modern than Bangkok. I feel pity for the condition of Bangalore when I compare it to Bangkok. Even if I compare the poshest portions of both cities, there is simply no comparison. Everything was absolutely top-notch - the roads, the traffic management, the comfort of pedestrians, and the traffic infrastructure. I especially loved the public transport of this city. It was functional and well-connected with each other. All three modes - buses, MTR and BTS function together in tandem to serve the city, which also helps in relieving the traffic on roads. Absolute beauty!!!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/bangkok-from-a-skybridge.Dm2Uca6m_Z10D17S.webp&quot; alt=&quot;Bangkok from a skybridge&quot; title=&quot;Bangkok from a skybridge&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;day-4&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#day-4&quot;&gt;Day 4&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The next day we reached Phuket airport to board our flight to Bangkok by 7.30 AM. We had to wait at the airport till 10 AM for the flight to take off. We reached Bangkok by 1.30 PM and took a Grab cab to our hotel. I liked the interface of Grab more than any other ride-hailing app I have used till now. It was easy to use and smooth (looking at you, Uber). The ride cost us ฿310, which is not that high if I compare it to the bus fare of ฿116 I paid while returning to the airport later in the trip.&lt;/p&gt;
&lt;p&gt;The hotel I booked was the Lyf Sukhumvit 8 Bangkok. The hotel looks nice on paper, but the lack of basic facilities and the farce of shared spaces (I assume this is to save costs) made it a not-so-value-for-money hotel for us. The room was tiny, particularly for a couple. There was no telephone, fridge or wardrobe in the room. You need to go to the reception to get all the necessary daily use items like towels, comb, toothbrushes, pen etc. It is usual for 3-star hotels to not provide these, but I haven&apos;t seen a 4-star hotel not providing them anywhere in the room. The bathroom was shared one - meaning that you can&apos;t use the toilet and bath area simultaneously because the door is sliding without locks.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/lyf-sukhumvit-8.6ML6g27s_Z1e2rBW.webp&quot; alt=&quot;Lyf Sukhumvit 8&quot; title=&quot;Lyf Sukhumvit 8&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4032&quot; height=&quot;3024&quot;&gt;&lt;/p&gt;
&lt;p&gt;However, there were some positives as well. The interior of the hotel was very innovative. The ideas of a shared kitchen and shared workspace on the ground floor were unique.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/interior-of-lyf-sukhumvit.BORg1YUK_ZRrT2q.webp&quot; alt=&quot;Interior of Lyf Sukhumvit&quot; title=&quot;Interior of Lyf Sukhumvit&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;As we left Phuket quite early, we didn&apos;t get a chance to have breakfast. So we were starving when we reached Bangkok. We decided to explore the hotel later and find a restaurant for quick lunch. We found Dosa King to be very near, so we proceeded to have lunch there. We liked this restaurant so much that we came here twice after this visit. The food here was excellent, the ambience was good, it didn&apos;t hurt our pockets much, and the owners were amiable.&lt;/p&gt;
&lt;p&gt;As we were filling our stomachs, we started looking for a nearby mall for a quick visit. And we found one at walking distance - Terminal 21. It is a massive mall with many shops selling various items, primarily apparel and related accessories.&lt;/p&gt;
&lt;h2 id=&quot;day-5&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#day-5&quot;&gt;Day 5&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The next day, we decided to roam the city on our own. We had a list of monuments ready to visit - Wat Pho, Wat Arun, Grand Palace, Emerald Buddha, and Wat Saket. The idea was to explore public transportation in Bangkok.&lt;/p&gt;
&lt;p&gt;We first boarded the MTR to reach Wat Pho. It was my first experience travelling on a metro train. I never found any need to travel in a metro in India. Bangkok has two types of metro - the overhead BTS and the underground MTR. We reached an MTR station and got the token by paying at an automatic vending machine. Next, we boarded the train, which was crowded, but still, the people organised themselves nicely.&lt;/p&gt;
&lt;p&gt;The day was very humid, and the sun was shining brightly. We were drenched during our short walk from the MTR station to Wat Pho. But alas, we reached there. The entry fee to Wat Pho was a whooping ฿200 per person, which is too high. But then I realised the entry fee for foreign tourists to enter historical monuments in Jaipur. And it all started making perfect sense.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/the-wat-pho-temple.fk1HXWzM_Z14qbn5.webp&quot; alt=&quot;The Wat Pho Temple&quot; title=&quot;The Wat Pho Temple&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;There are many Buddhist temples on the premises of Wat Pho. We got bored walking around because we didn&apos;t opt for a guide. Nothing made any sense as we were not familiar with the history. But I guess, even with a guide, my feelings would not have been any different.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/buddha-shrine-at-the-wat-pho-temple.D3twwszj_sVNIH.webp&quot; alt=&quot;Buddha Shrine at The Wat Pho Temple&quot; title=&quot;Buddha Shrine at The Wat Pho Temple&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;After our experience of Wat Pho, we decided to rethink our visit to Grand Palace. Seeing the considerable entry fee of ฿500 and an expectation of an experience similar to Wat Pho, we decided it was best to go to something other than Grand Palace. But mind it, the Grand Palace is the most visited tourist attraction in Bangkok, and if you are interested in museums, you should definitely see it.&lt;/p&gt;
&lt;p&gt;Next, we decided to visit Wat Arun across the Chao Phraya River. It was a long walk to reach the boat ferry. It is yet another overcrowded Buddhist temple with people doing photoshoots in traditional Thai costumes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/wat-arun-entry-ticket.CAh3iWRl_ZgxdK8.webp&quot; alt=&quot;Wat Arun Entry Ticket&quot; title=&quot;Wat Arun Entry Ticket&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/wat-arun-temple.CNYzODeE_Z1UnD5S.webp&quot; alt=&quot;Wat Arun Temple&quot; title=&quot;Wat Arun Temple&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;From Wat Arun, we decided to go to Wat Saket. To reach Wat Saket, we had to take another ferry to go back to the other side of the city and then board a bus to Democracy Monument and then walk from there.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/a-regular-bus-in-bangkok.giMSeTiw_1w1vGD.webp&quot; alt=&quot;A regular bus in Bangkok&quot; title=&quot;A regular bus in Bangkok&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/ferry-tickets.B6cqdlIh_1k4bxe.webp&quot; alt=&quot;Ferry tickets&quot; title=&quot;Ferry tickets&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;While we were walking towards Wat Saket, we found another attraction - the &lt;a href=&quot;https://goo.gl/maps/XjCRbvcnZKLmWo4J6&quot;&gt;Statue of King Rama III&lt;/a&gt;. It was a nice little resting point for us with some good photo points.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/statue-of-king-rama-iii.CsV2UTd7_YfL0m.webp&quot; alt=&quot;Statue of King Rama III&quot; title=&quot;Statue of King Rama III&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;We wanted to go to Wat Saket as it is termed a good sunset point by many online blogs. Unfortunately, when we reached there, the weather had turned cloudy, and the sun was nowhere in sight. We waited there for 2 hours for the sun to show up, but this didn&apos;t happen, and we had to return disappointed. Nevertheless, we clicked some lovely pictures.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/entry-of-the-golden-mount-wat-saket.BuLPAsZS_2qlNTT.webp&quot; alt=&quot;Entry of The Golden Mount (Wat Saket)&quot; title=&quot;Entry of The Golden Mount (Wat Saket)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/bangkok-from-the-top-of-wat-saket.Z5Pq84n0_1uQ3Cc.webp&quot; alt=&quot;Bangkok from the top of Wat Saket&quot; title=&quot;Bangkok from the top of Wat Saket&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4032&quot; height=&quot;3024&quot;&gt;&lt;/p&gt;
&lt;p&gt;After Wat Saket, we decided to call it a day, and returned to our hotel after having dinner at &lt;a href=&quot;https://goo.gl/maps/Eusnar8ZQyyA9ep18&quot;&gt;Saras Veg Food&lt;/a&gt;. This was our most expensive dinner on the trip, but I found the food average.&lt;/p&gt;
&lt;p&gt;While walking to Saras Restaurant, we stumbled upon an Ardhanarishvara statue on a busy street. I was pleasantly surprised to see this. You perhaps won&apos;t find this iconography in many places in India.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/ardhanarishvara-shrine.BOot68xp_Z1FrOq0.webp&quot; alt=&quot;Ardhanarishvara Shrine&quot; title=&quot;Ardhanarishvara Shrine&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;day-6&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#day-6&quot;&gt;Day 6&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The next day of our trip was solely reserved for mall visits. Bangkok is known for its huge malls, and we decided to spend one day visiting them. We didn&apos;t have anything specific in mind for shopping. We visited the Platinum Mall, the Palladium Mall, The City Complex and The Market. We completely missed Central World, the largest mall in Bangkok. It never came up in our research somehow. We will visit it someday, hopefully.&lt;/p&gt;
&lt;p&gt;After having dinner at &lt;a href=&quot;https://goo.gl/maps/hycc8ypbUzRtBh2f7&quot;&gt;Maa Pure Vegetarian Indian Restaurant&lt;/a&gt;&lt;strong&gt;,&lt;/strong&gt; we decided to walk to the bus stand. On our way, we passed through &lt;a href=&quot;https://goo.gl/maps/Lf9pjM2F34RgNacPA&quot;&gt;Baiyoke Night Market&lt;/a&gt;, which is a wholesale cloth market. I saw a lot of Indians shopping there. As there was a light shower, we decided to leave the place and reach the bus stop quickly.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/baiyoke-night-market.BBc8bZ3Y_1DRw13.webp&quot; alt=&quot;Baiyoke Night Market&quot; title=&quot;Baiyoke Night Market&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;day-7&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#day-7&quot;&gt;Day 7&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The day brought an end to our visit to Thailand. The next day, though our flight was for 7.30 PM in the evening, we packed our luggage, had an early lunch at Dosa King (again) and left for DMK airport by around 1.00 PM to avoid paying the hotel for one extra day. We had to wait outside airport security for 3 hours before our luggage was checked in. Once we cleared the airport security, we decided to go to Miracle Lounge and sit until our boarding started. However, our flight got delayed due to technical issues, and we reached Jaipur Airport late by 2 hours.&lt;/p&gt;
&lt;h1 id=&quot;cost-breakdown&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#cost-breakdown&quot;&gt;Cost Breakdown&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We jumped our initial estimation by around 10%, primarily because of the costs incurred due to the rescheduling of flights. As there were four flights in our itinerary, the costs increased significantly. We could have planned it better by booking Jaipur to Phuket and Bangkok to Jaipur flights. But Jaipur to Bangkok return flights were cheaper when we booked them initially.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/category-wise-money-spent.Cc3tHr51_Z1UqStu.webp&quot; alt=&quot;Category wise money spent&quot; title=&quot;Category wise money spent&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;600&quot; height=&quot;371&quot;&gt;&lt;/p&gt;
&lt;p&gt;Our next significant expense was on hotels, food and activities. I found The Silver Resortel for a reasonable price, but the decision to opt for Lyf could have been better. We spent most of our daytime outside the hotel, so we could have stayed in a 3-star hotel for a much lower price.&lt;/p&gt;
&lt;p&gt;We wanted to eat in vegetarian restaurants only. And vegetarian restaurants in Thailand are rare. Due to this, the cost of eating in such restaurants is high. As the demand is high, restaurants serve non-vegetarian food to every stratum of society. But, these Indian vegetarian restaurants have to aim at tourists only due to less local demand. So accordingly, their prices are high as well. We had to spend around ฿1000 a day on food, despite eating homemade thepla for breakfast for the first 3 days of our trip.&lt;/p&gt;
&lt;p&gt;Activities in Phuket were another significant expense. These could not be avoided, and by going in the low season, we saved quite a bit on it. According to some YouTube blogs, what we did for ฿1250 requires at least ฿1700-1800 in the regular season. So definitely, we saved a bit here.&lt;/p&gt;
&lt;p&gt;We found the shopping to be expensive there. I don&apos;t know why people go to Bangkok to buy stuff. I found everything to be costly by Indian standards. It may be futile to convert everything into INR, or perhaps people want to feel nostalgic about Bangkok by buying stuff. Nevertheless, we didn&apos;t purchase many unnecessary things and spent only on souvenirs for friends and family.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We missed visiting many attractions in Bangkok and Phuket, most notably Phuket Old Town, James Bond Islands, Karon Beach, Kata Beach in Phuket and Central World and various Night Markets in Bangkok. Still, there will always be such things in a travel plan. You simply can&apos;t cover everything.&lt;/p&gt;
&lt;p&gt;Nevertheless, Thailand was my first international trip, which will always be memorable for this reason alone. I loved visiting this amazing country, and the hospitality of the Thai people really won me. I plan to come to Thailand again to explore its northern ends soon.&lt;/p&gt;</content:encoded></item><item><title>India turns 77!</title><link>https://yashagarwal.in/notes/india-turns-77/</link><guid isPermaLink="true">https://yashagarwal.in/notes/india-turns-77/</guid><description>Reflecting on India&apos;s 77th Independence Day, this post explores national progress, cultural shifts, and the evolving concept of patriotism.</description><pubDate>Tue, 15 Aug 2023 16:25:24 GMT</pubDate><content:encoded>&lt;p&gt;India is celebrating its 76th independence day today. Irrespective of all the political gimmicks (like per capita GDP vs total size of economy), there is no doubt about India’s economic progress and cultural awakening in the present times. However, we must be careful not to turn in religious bigots. This is not the characteristic of our culture, at least for the last millennium.&lt;/p&gt;
&lt;p&gt;With all the negativity surrounding us in the current environment, I wonder if a symbolism like Independence Day is of value anymore. There used to be a time when my school used to have a function on two days of national importance. There used to be intense preparations for the day for the preceding one month. On the day of the event, we used to get ready early and leave for school in anticipation of some cultural activities, prize distributions, dreaded Yoga activities, and not the least, laddus! There used to be some energetic patriotic sermons from local leaders and persons of eminence. It was an excellent introduction to cultural patriotism for us kids, away from all the intricacies and complexities of the culture, nation, and the ultra-modern concept of patriotism. I can’t help but reminisce about the time gone by.&lt;/p&gt;
&lt;p&gt;Yesterday, I was talking to my cousin, who has two kids. He mentioned that there is no cultural activity in his son’s school this time. School administration no longer wants to indulge in such activities due to mounting expenses. I couldn’t help but wonder how the child will develop a sense of patriotism (it is another debate if creating such a feeling is necessary or not). If the state is no longer interested in teaching the feeling of belongingness to the nation, how will future citizens behave when they have the command? There are many reasons for people to break away from this nation; why do we want to create one more? Politicians are busy with their agenda. When I opened a Hindi daily today, I found only the advertisements for Government’s latest schemes. They find it enough to mention Independence Day in passing.&lt;/p&gt;
&lt;p&gt;People still curse the English for what all wrong was done to Indians for 190+ years till 1947. I don’t understand the &lt;em&gt;nostalgia&lt;/em&gt;. What happened was wrong, and we must ensure that history doesn’t repeat itself. But complaining about it will not benefit us as a nation. Nowadays, it is commonplace to bash people of the past for all that is wrong with India today. I am a firm believer in the fact that one should not judge the past through the moral yardsticks of the present. Using history to justify today’s politics won’t benefit India. Indians as a people have evolved a lot since 1947. What was right in 1947 may not be right in the present. The decisions leaders took at that time may not be consistent with the facts available today. They must have made a lot of wrong decisions. They made some blunders. They were wrong in a lot of their judgments. But does it matter anymore? Can we pull an Endgame-like Time Heist and put things back in place? Why do we still cry over what happened 75 years ago if not? People talk about Akhanda Bharata and all the nostalgia surrounding it. Suppose all the people today living in the so-called Akhanda Bharata areas come back to join us. Is India capable enough to sustain herself and not die beneath the weight of religious bigotry? The advent of the Internet and social media seems to have aggravated the religious zeal that is unlikely to calm down in times to come.&lt;/p&gt;
&lt;p&gt;Despite all the flaws in India as a nation and political system, I am very optimistic about its future. The country has done great on many of the UN’s sustainable development goals. There is much to achieve, but we are moving in the correct direction. Reservation system, religious attitudes of people, and shady politicians fuelling all kinds of partisanship in the people are the biggest threats to India and her future. While I understand the atrocities done on certain sections of Indian society in the past, I wonder if the time is ripe for overhauling the reservation system to make it more beneficial for needy sections of the society. We seem to be moving in another direction where the more the population of a caste, the more reservation it will get, irrespective of the political clout and financial status of its people. I believe this is a recipe for disaster in times to come. It is the age of science and technology. Suppose people get to the upper echelons of the scientific and technical community based on their castes and not their academic performance. In that case, we may be delayed in getting our rightful place (of Vishwa Guru, as the RW likes to term it) in the world. I know that with this biased opportunity system, we have brought many previously deprived yet talented people to the forefront, and education definitely improved their conditions generation after generation. Similarly, perhaps a few generations later, we will reach the top of the world order. But will we have the kind of demographic dividend then? I am doubtful.&lt;/p&gt;
&lt;p&gt;Until next time 🇮🇳🇮🇳🇮🇳&lt;/p&gt;</content:encoded></item><item><title>Add reading time to blog articles</title><link>https://yashagarwal.in/notes/add-reading-time-to-blog-articles/</link><guid isPermaLink="true">https://yashagarwal.in/notes/add-reading-time-to-blog-articles/</guid><description>Learn to add estimated reading time to your blog articles using Contentlayer and a simple NPM package for enhanced user experience.</description><pubDate>Sat, 05 Aug 2023 17:57:24 GMT</pubDate><content:encoded>&lt;p&gt;This article will show how to add estimated reading time to your posts. This is pretty easy to achieve with Contentlayer’s computed fields.&lt;/p&gt;
&lt;p&gt;This article assumes that you have read my &lt;a href=&quot;https://yashagarwal.in/notes/integrating-contentlayer-with-nextjs-blog&quot;&gt;previous post&lt;/a&gt; and integrated Contentlayer into your project accordingly. We will build upon the foundations laid in the last article and add a new computed field to the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Post&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; document type to display the estimated reading time of the article to the readers.&lt;/p&gt;
&lt;h1 id=&quot;how-to-compute-reading-time&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#how-to-compute-reading-time&quot;&gt;How to compute reading time?&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Computing the reading time of any text content requires two things -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The text content itself, which, thanks to Contentlayer, is available to us in raw form in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;post.body.raw&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; where &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;post&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is the JSON parsed by &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;contentlayer&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; from the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;mdx&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file.&lt;/li&gt;
&lt;li&gt;An algorithm to calculate the reading time&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We can come up with our own &lt;a href=&quot;https://www.freecodecamp.org/news/how-to-more-accurately-estimate-read-time-for-medium-articles-in-javascript-fb563ff0282a/&quot;&gt;algorithm&lt;/a&gt; or use a package to do the heavy lifting for us. A number of packages exist on the NPM registry to help with this task -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/reading-time&quot;&gt;reading-time&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pritishvaidya/read-time-estimate&quot;&gt;read-time-estimate&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;read-time-estimate&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; appears to be a more complete package that also takes image read times into consideration, but I am not sure if it is meant as a ready-to-use package. At least I couldn’t get it to work with my setup. So, I decided to go with &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;reading-time&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, a far more popular package.&lt;/p&gt;
&lt;h1 id=&quot;adding-a-new-computed-field&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#adding-a-new-computed-field&quot;&gt;Adding a new computed field&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;After finalising the package to use, it’s time to install it. I will use &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;yarn&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to install the package. You can find a similar command for your package manager.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;yarn&lt;/span&gt; add -D reading-time&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This will install &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;reading-time&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; as a dev-dependency in our project, which is fine given that we will only be utilising this package at build time.&lt;/p&gt;
&lt;p&gt;Once installed, it is time to import and use it in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;contentlayer.config.js&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;jsx&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-line-numbers=&quot;&quot; data-language=&quot;jsx&quot; data-theme=&quot;github-dark-dimmed github-light&quot; data-line-numbers-max-digits=&quot;2&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; { defineDocumentType, makeSource } from &quot;contentlayer/source-files&quot;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; readingTime from &quot;reading-time&quot;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;const&lt;/span&gt; Post = defineDocumentType(() =&gt; ({
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  name: &lt;/span&gt;&quot;Post&quot;,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  filePathPattern: &lt;/span&gt;&quot;posts/*.mdx&quot;,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  contentType: &lt;/span&gt;&quot;mdx&quot;,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  fields: {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    title: { type: &lt;/span&gt;&quot;string&quot;, required: true },
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    published: { type: &lt;/span&gt;&quot;string&quot;, required: true },
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    description: { type: &lt;/span&gt;&quot;string&quot; },
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    status: {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      type: &lt;/span&gt;&quot;enum&quot;,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      options: [&lt;/span&gt;&quot;draft&quot;, &quot;published&quot;],
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      required: &lt;/span&gt;true,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  computedFields: {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    slug: {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      type: &lt;/span&gt;&quot;string&quot;,
&lt;span style=&quot;--shiki-dark:#DCBDFB;--shiki-light:#6F42C1&quot;&gt;      resolve&lt;/span&gt;: (doc) =&gt; doc._raw.sourceFileName.replace(/\.mdx$/, &quot;&quot;),
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    readingTime: {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      type: &lt;/span&gt;&quot;json&quot;,
&lt;span style=&quot;--shiki-dark:#DCBDFB;--shiki-light:#6F42C1&quot;&gt;      resolve&lt;/span&gt;: (doc) =&gt; readingTime(doc.body.raw),
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}))&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;export&lt;/span&gt; default makeSource({
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  contentDirPath: &lt;/span&gt;&quot;content&quot;,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  documentTypes: [Post]&lt;/span&gt;,
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#24292E&quot;&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;rendering-it&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#rendering-it&quot;&gt;Rendering it&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;In the generated JSON files, we will have the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;readingTime&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; property available for use in the components.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;json&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-line-numbers=&quot;&quot; data-language=&quot;json&quot; data-theme=&quot;github-dark-dimmed github-light&quot; data-line-numbers-max-digits=&quot;2&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;{&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;title&quot;&lt;/span&gt;: &quot;Hello World&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;published&quot;&lt;/span&gt;: &quot;2023-07-30T13:05:24.000Z&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;status&quot;&lt;/span&gt;: &quot;published&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;body&quot;&lt;/span&gt;: {
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;raw&quot;&lt;/span&gt;: &quot;\nHello world! This is my first post.\n&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;code&quot;&lt;/span&gt;: &quot;var Component=(()=&gt;{var sr=Object.create;...&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;_id&quot;&lt;/span&gt;: &quot;posts/hello-world.mdx&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;_raw&quot;&lt;/span&gt;: {
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;sourceFilePath&quot;&lt;/span&gt;: &quot;posts/hello-world.mdx&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;sourceFileName&quot;&lt;/span&gt;: &quot;hello-world.mdx&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;sourceFileDir&quot;&lt;/span&gt;: &quot;posts&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;contentType&quot;&lt;/span&gt;: &quot;mdx&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;flattenedPath&quot;&lt;/span&gt;: &quot;posts/hello-world&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;readingTime&quot;&lt;/span&gt;: {
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;text&quot;&lt;/span&gt;: &quot;1 min read&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;minutes&quot;&lt;/span&gt;: 0.035,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;time&quot;&lt;/span&gt;: 2100,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;words&quot;&lt;/span&gt;: 7
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;type&quot;&lt;/span&gt;: &quot;Post&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;slug&quot;&lt;/span&gt;: &quot;hello-world&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;To use it in the component, we can use the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;post.readingTime.minutes&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; property to show the time-to-read, something like this (here &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;post&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; contains the JSON data shown above) -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;p&gt;Time to read: {Math.round(post.readingTime.minutes)} mins&amp;#x3C;/p&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;</content:encoded></item><item><title>Half a Decade in Tech</title><link>https://yashagarwal.in/notes/half-a-decade-in-tech/</link><guid isPermaLink="true">https://yashagarwal.in/notes/half-a-decade-in-tech/</guid><description>Reflecting on five years in the tech industry, this post shares insights on coding, team dynamics, and personal growth.</description><pubDate>Thu, 03 Aug 2023 10:18:46 GMT</pubDate><content:encoded>&lt;p&gt;I completed five years in the tech industry on August 1. I started out as a fresher straight out of college. I had no &lt;a href=&quot;https://yashagarwal.in/notes/beginning-a-new-journey&quot;&gt;idea&lt;/a&gt; how the journey would turn out to be. I have sailed smoothly through the last five years by God&apos;s grace. Although I sometimes feel left behind compared to my peers in career growth, my personal metrics of personal development have largely been on the positive side (worth mentioning that I have evolved the way I look at personal growth as well.)&lt;/p&gt;
&lt;p&gt;Often, I struggled with the feeling that I was not fit for this industry. My peers are doing great in their roles, achieving promotions year after year, running side gigs, moving to the US - earning in dollars and getting exposure to the Bay Area. I felt like missing out on great things in life. Whenever I open Instagram or LinkedIn, I see people enjoying their lives to the fullest. Of course, I know that what I see may not be the reality. Still, I couldn&apos;t help but doubt my capabilities.&lt;/p&gt;
&lt;p&gt;That&apos;s how life plays out. Some days are bright and sunny. On these days, you feel like that king who can&apos;t do anything wrong. On the other hand, there are those gloomy days when you wake up doubting yourself. Nothing goes your way. You feel pathetic, and helplessness clouds your judgement. It is on these days when you will find the real &lt;em&gt;&lt;strong&gt;you&lt;/strong&gt;&lt;/em&gt;. How you handle these days will make or break you.&lt;/p&gt;
&lt;p&gt;I have become a different person from what I was five years ago. The tech industry has transformed me to a great extent. I am more confident, concentrated and mature. I am rediscovering the long-missing criticality in my thought process. I have learnt to be satisfied running the &lt;em&gt;race&lt;/em&gt; at my own pace. I am working slowly but steadily on my future. And I am proud to claim that I am better mentally and physically than five years ago. &lt;strong&gt;I believe this is the most appropriate criterion to determine my success.&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&quot;coding-is-the-easiest&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#coding-is-the-easiest&quot;&gt;Coding is the easiest&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;When I was in college, coding felt like the most challenging task. I was afraid that I would not be able to manage the expectations of my future teams. Turns out, I was wrong. Writing code is easy, maintaining it is harder and convincing people the hardest.&lt;/p&gt;
&lt;p&gt;Maintaining the code takes a lot of effort and patience if not done correctly right from the first commit. Customer demands and internal requirements change over time. Your team changed its size and shape, and the persons who wrote that library are no longer with the company. Without proper documentation and UTs, it gets difficult for newcomers to take ownership without an upfront investment of significant human hours. Unfortunately, this is how it works in most tech teams, and the only way to get the work done is to get your hands dirty with code.&lt;/p&gt;
&lt;p&gt;One of the best compliments I received was from one of my managers. He told me -&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;On my commits, QA doesn’t have to worry about doing deep validations because of the extensive testing I perform on my code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In fact, in my last 1.5 years at Netskope, I have been responsible for only two regressions - the first happened in my first week at the company and another a year later because I was unaware of that particular code path.&lt;/p&gt;
&lt;p&gt;People are the toughest nuts to crack. Early in my career, I used to try to convince my seniors at face value without any research. Over time, I learnt that it is easier to convince people when you have data. &lt;strong&gt;Substantiate your claims with solid data.&lt;/strong&gt; They will listen. The seniors, who, I thought, were hurdles in my growth, were just trying to do their jobs. I have grown strong empathy for the management in these years. As a result, I find it easy to talk with them after I have done my due diligence and collected enough data to support my propositions. Unlike code, people behave differently according to the situation. &lt;strong&gt;The faster one adopts to handle people, the faster one grows.&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&quot;if-you-dont-ask-you-dont-get&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#if-you-dont-ask-you-dont-get&quot;&gt;If you don’t ask, you don’t get&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;In a typical tech team at a reputable company, everybody is a top talent. Everybody wants to reach the next level; hence the competition is steep. When everybody is trying their best to achieve that next promotion, it is difficult to get it without non-work effort. That is where the people skills come in handy.&lt;/p&gt;
&lt;p&gt;My feeling of FOMO comes from the fact that I never sought any kind of promotion or pay raise at work. I always trusted my managers to do the heavy lifting, which never worked. If I don’t ask for it, it doesn’t mean nobody else does too. And the managers prefer those performing at my level and have also explicitly requested promotion. I have been trying to change this for the last few months. Being vocal about your work is a necessity to reach the next level.&lt;/p&gt;
&lt;h1 id=&quot;customer-first&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#customer-first&quot;&gt;Customer first&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Businesses need to generate a profit. No matter how world-class my product is, whether you use cutting-edge tech in developing your products, customers don’t care. They don’t care if you are following all the best practices in the world. They only care about getting their work done; if your product is not helping, it is useless for them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For a business, the latest and greatest doesn’t matter as much as getting the shit done.&lt;/strong&gt; If you can’t deliver on time, you will lose the race. Customers love quality but also want to see things working as quickly as possible. It is not that your work is over once the product is shipped. After deployment, subsequent support is equally important. There are SLAs to honour, bugs to be fixed, and those weird customer requirements you couldn’t guess during those first architecture design meetings. Things often go wrong, and you must fix these to win that new contract next year.&lt;/p&gt;
&lt;h1 id=&quot;is-work-life-balance-a-myth&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#is-work-life-balance-a-myth&quot;&gt;Is Work-Life Balance a myth?&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I have been fortunate to have jobs with an excellent work-life balance in the last five years. Rarely I had to work on weekends. Work does get spilled to after-work-hours at least once every few days. However, even then, I get a lot of free time. But I did not utilise this time properly. If I had used my time correctly, I could’ve learnt a lot of new stuff (hobbies and work-related).&lt;/p&gt;
&lt;p&gt;My focus in the last five years has been on various non-tech things. For some reason, staying in touch with the latest tech never became my top priority. It is only in the last few months that I have started to explore again, perhaps because I have realised the importance of it for the next-level transition. As a side-effect, I expect an improvement in the activity on this blog as well.&lt;/p&gt;
&lt;p&gt;On-calls are another aspect of a job at some software companies. I got introduced to it at Netskope, where every developer has to be on-call for one week continuously once every two-three months. Being on-call comes with a specific stress level. Still, it is a great learning opportunity to get to know the product from a critical standpoint. Although I don’t enjoy it very much, it is part and parcel of the job, so I can’t ignore it either.&lt;/p&gt;
&lt;h1 id=&quot;remote-work-is-the-future-but-&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#remote-work-is-the-future-but-&quot;&gt;Remote work is the future but …&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Since the pandemic, remote work has picked up pace. I have been working remotely for the last three years, and while I enjoy it, I am concerned about my career growth. Looking at the state of big tech, I am uncertain for how long the rest of the industry will be willing to continue with remote work. On the other hand, due to the resistance shown by the big tech towards remote work, there may be a significant drift of talent towards more-remote friendly companies.&lt;/p&gt;
&lt;p&gt;Remote work suits well to someone like me, who is appalled by the pathetic state of infrastructure and quality of life in the major Indian tech cities. Unless the state of affairs in these cities improves, I find it difficult to even think of moving back. However, having a job is the prime concern, and any probable threat to my job because of remote work may be a compelling reason to consider moving back. But until then, Jaipur is the best.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;There is still a long journey left for me in the industry. Five years in tech is like a lifetime. It sometimes becomes challenging to keep up with the rapid changes in the tech world. With the advent of AI, it may become even more difficult for knowledge workers to stay relevant. Instead of running behind every latest framework, sticking to the basics would be a good idea for me. Frameworks may come and go, but basics will always stay in fashion.&lt;/p&gt;
&lt;p&gt;Hoping to be at my best in the years to come &lt;strong&gt;🥳&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title>Image Component in Next.js</title><link>https://yashagarwal.in/notes/image-component-in-nextjs/</link><guid isPermaLink="true">https://yashagarwal.in/notes/image-component-in-nextjs/</guid><pubDate>Sun, 30 Jul 2023 13:10:24 GMT</pubDate><content:encoded/></item><item><title>RSS feeds in Next.js blog</title><link>https://yashagarwal.in/notes/rss-feeds-in-nextjs-blog/</link><guid isPermaLink="true">https://yashagarwal.in/notes/rss-feeds-in-nextjs-blog/</guid><pubDate>Sun, 30 Jul 2023 13:10:24 GMT</pubDate><content:encoded/></item><item><title>Integrating Contentlayer with Next.js Blog</title><link>https://yashagarwal.in/notes/integrating-contentlayer-with-nextjs-blog/</link><guid isPermaLink="true">https://yashagarwal.in/notes/integrating-contentlayer-with-nextjs-blog/</guid><description>Learn how to integrate Contentlayer with a Next.js blog, streamlining content management and leveraging modern web development tools.</description><pubDate>Sun, 30 Jul 2023 13:00:24 GMT</pubDate><content:encoded>&lt;p&gt;The second part of this series explores Contentlayer and how to integrate it with a Next.js blog. I will elaborate on my experience managing content on my blog throughout the last eight years using various tools, why I decided to use Contentlayer and how to integrate it into a Next.js blog.&lt;/p&gt;
&lt;h1 id=&quot;history&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#history&quot;&gt;History&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;When I was starting out on my journey with Next.js to build the next version of my blog, I had to figure out a way to feed data into my application. I used only traditional static site generators like Jekyll and Hugo until then. SSGs work in this way - One writes the content in local markdown files; the SSG takes these files, extract the front matter and actual body, converts the extracted information to variables and feeds them into the actual server-side rendering logic, which will generate the static HTML files. Storing these content markdown files in Git is what is today called the &lt;strong&gt;Git CMS&lt;/strong&gt;. I am a big proponent of keeping the content in a Git repository because it makes it easier to track the writing journey without tying too much into a vendor.&lt;/p&gt;
&lt;p&gt;Although the concept of SSGs came into being with the release of Jekyll in 2008 (at the same time as Github and its iconic &lt;a href=&quot;https://docs.github.com/en/pages/quickstart&quot;&gt;Pages&lt;/a&gt; feature), I actually started my journey with it in 2015. Since then, technology has advanced by leaps and frogs, and several new approaches to managing content and code have emerged.&lt;/p&gt;
&lt;p&gt;I also dabbled with integrating headless CMS (&lt;a href=&quot;https://wordpress.com/&quot;&gt;WordPress&lt;/a&gt;, &lt;a href=&quot;https://www.sanity.io/&quot;&gt;Sanity&lt;/a&gt; and &lt;a href=&quot;https://www.contentful.com/&quot;&gt;Contentful&lt;/a&gt;) and GraphQL based &lt;a href=&quot;https://www.gatsbyjs.com/&quot;&gt;Gatsby&lt;/a&gt; at various points in past few years, however I was never successful because of my unease with JavaScript. My unwillingness to rely on any third-party vendor for storing my content and the costs associated with self-hosting any open source CMS also contributed greatly to my failure to transition.&lt;/p&gt;
&lt;h1 id=&quot;migrating-to-nextjs&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#migrating-to-nextjs&quot;&gt;Migrating to Next.js&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;When I was starting to migrate my blog to Next.js, I had a couple of requirements in mind -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I preferred using a headless CMS for storing the content. A few reasons are -
a. My writing was already suffering because of my over-emphasis on coding instead of writing.
b. I was somewhat frustrated with my blog&apos;s overly complicated publishing process.&lt;/li&gt;
&lt;li&gt;The CMS should allow export in popular open formats when I decide to migrate in future.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Notion fits nicely into my requirements. It has a well-defined (although with poor performance) &lt;a href=&quot;https://developers.notion.com/&quot;&gt;API&lt;/a&gt;. It is a popular tool with the developer community and offers the export of the content in markdown format. Notion would have worked well for my requirements, but I couldn&apos;t integrate it properly with my blog due to my lack of JavaScript experience.&lt;/p&gt;
&lt;p&gt;So, I reverted back to using markdown for my blog&apos;s content. I still write in Notion&apos;s excellent editor but then export the file to markdown and manually edit image paths etc., to work with my blog&apos;s structure.&lt;/p&gt;
&lt;p&gt;However, using &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;md&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and its more advanced sibling &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;mdx&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; with Next.js is tedious and error-prone. A bunch of tools need to be integrated to make MDX work with Next.js. &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;unified&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;remark&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;rehype&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; ecosystem provides some great tools, but combining these is not trivial. I had already wasted enough time struggling with Notion. I might have abandoned the project altogether if I had wasted a few more days.&lt;/p&gt;
&lt;p&gt;My search finally ended on &lt;a href=&quot;https://www.contentlayer.dev/&quot;&gt;Contentlayer&lt;/a&gt;. Contentlayer is a tool which transforms unstructured markdown content into structured type-safe JSON data structures and provides accessible interfaces to access these data structures. This means I could import all my content in the code files using an &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; statement and work with the data as if working with a Typescript interface. This eliminated the need to struggle with additional boilerplate code needed to use the low-level libraries to interact with the MDX files.&lt;/p&gt;
&lt;p&gt;With that in mind, let&apos;s see how to integrate Contentlayer in our Next.js blog. In later posts of this series, we will also see how to utilise the extensive plugin ecosystem provided by the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;unified&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; project to enrich the data interfaces exposed by Contentlayer.&lt;/p&gt;
&lt;h1 id=&quot;install-and-configure-contentlayer&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#install-and-configure-contentlayer&quot;&gt;Install and Configure Contentlayer&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Contentlayer&apos;s &lt;a href=&quot;https://www.contentlayer.dev/docs/getting-started-cddd76b7&quot;&gt;getting started&lt;/a&gt; guide is a good resource to setup your Next.js project to work with Contentlayer. I have described the same steps below for quick reference -&lt;/p&gt;
&lt;p&gt;First, add &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;contentlayer&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;next-contentlayer&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to the project -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-line-numbers=&quot;&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot; data-line-numbers-max-digits=&quot;1&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;yarn&lt;/span&gt; add contentlayer next-contentlayer&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;next-contentlayer&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; provides an &lt;a href=&quot;https://www.contentlayer.dev/docs/reference/next-contentlayer-e6e7eb3a#withcontentlayer&quot;&gt;API&lt;/a&gt; to stitch together &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;next&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;contentlayer&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; by hooking into the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;next dev&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;next build&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; commands. This will ensure that &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;contentlayer&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; runs automatically for local development and production deployments.&lt;/p&gt;
&lt;p&gt;Now, we need to patch the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;next.config.js&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to use the API provided by the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;next-contentlayer&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to hook into the commands mentioned above -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;jsx&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-line-numbers=&quot;&quot; data-language=&quot;jsx&quot; data-theme=&quot;github-dark-dimmed github-light&quot; data-line-numbers-max-digits=&quot;1&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;// next.config.js&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;const&lt;/span&gt; { withContentlayer } = require(&quot;next-contentlayer&quot;)
 
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;module&lt;/span&gt;.exports = withContentlayer(nextConfig)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;content-schema&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#content-schema&quot;&gt;Content Schema&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Once we have &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;contentlayer&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; setup, it is time to define the structure of our data that will be used by Contentlayer to parse the MDX files. Contentlayer can also process the parsed content to derive new fields. Let&apos;s see how it is done.&lt;/p&gt;
&lt;p&gt;Create a new file, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;contentlayer.config.js&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, in the root of your project. Inside this file, I am defining a &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Post&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; document type -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;jsx&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-line-numbers=&quot;&quot; data-language=&quot;jsx&quot; data-theme=&quot;github-dark-dimmed github-light&quot; data-line-numbers-max-digits=&quot;2&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; { defineDocumentType, makeSource } from &quot;contentlayer/source-files&quot;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;export&lt;/span&gt; const Post = defineDocumentType(() =&gt; ({
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;  // The name of the document type&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  name: &lt;/span&gt;&quot;Post&quot;,
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;  // The type of the files to parse. &apos;md&apos; also works&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  contentType: &lt;/span&gt;&quot;mdx&quot;,
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;  // The path of the mdx files, relative to contentDirPath&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  filePathPattern: &lt;/span&gt;&quot;posts/*.mdx&quot;,
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;  // Fields present in the frontmatter of the MDX file&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  fields: {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    title: { type: &lt;/span&gt;&quot;string&quot;, required: true },
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    published: { type: &lt;/span&gt;&quot;string&quot;, required: true },
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    description: { type: &lt;/span&gt;&quot;string&quot; },
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    status: {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      type: &lt;/span&gt;&quot;enum&quot;,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      options: [&lt;/span&gt;&quot;draft&quot;, &quot;published&quot;],
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      required: &lt;/span&gt;true,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}))&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;export&lt;/span&gt; default makeSource({
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  contentDirPath: &lt;/span&gt;&quot;content&quot;,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  documentTypes: [Post]&lt;/span&gt;,
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#24292E&quot;&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;In the code snippet above, the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;fields&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; key is used to store the &lt;a href=&quot;https://www.contentlayer.dev/docs/reference/source-files/field-types-defe41e9&quot;&gt;custom fields&lt;/a&gt; related to the metadata of a post, such as title, publish date etc. Any field can be made mandatory by using &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;required: true&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Now, create a folder called &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;content&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; in the project&apos;s root, and inside this folder, create a subfolder called &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;posts&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. We will store the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;mdx&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; files inside this folder. Let&apos;s start our first post, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;content/posts/hello-world.mdx&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;markdown&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-line-numbers=&quot;&quot; data-language=&quot;markdown&quot; data-theme=&quot;github-dark-dimmed github-light&quot; data-line-numbers-max-digits=&quot;1&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;---&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;title&lt;/span&gt;: Hello World
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;published&lt;/span&gt;: 2023-07-30T13:05:24.000Z
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;status&lt;/span&gt;: published
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;---&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;Hello world! This is my first post.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;If &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;next dev&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is running in the background while you save this file, you will see the following output in your terminal -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;txt&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-line-numbers=&quot;&quot; data-language=&quot;txt&quot; data-theme=&quot;github-dark-dimmed github-light&quot; data-line-numbers-max-digits=&quot;1&quot;&gt;&lt;span&gt;wait - compiling...&lt;/span&gt;
&lt;span&gt;File updated: content/posts/hello-world.mdx&lt;/span&gt;
&lt;span&gt;Generated 1 document in .contentlayer&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;contentlayer-artifacts&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#contentlayer-artifacts&quot;&gt;Contentlayer Artifacts&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;When &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;next dev&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is run for the first time after setting up Contentlayer, Contentlayer creates a hidden folder inside the project root directory - &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;.contentlayer&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. All the processed files, generated data structures, and helper functions and interfaces are stored here. Let&apos;s see the contents of this directory -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;txt&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-line-numbers=&quot;&quot; data-language=&quot;txt&quot; data-theme=&quot;github-dark-dimmed github-light&quot; data-line-numbers-max-digits=&quot;2&quot;&gt;&lt;span&gt;❯ tree&lt;/span&gt;
&lt;span&gt;./&lt;/span&gt;
&lt;span&gt;├── .contentlayer/&lt;/span&gt;
&lt;span&gt;│   ├── generated/&lt;/span&gt;
&lt;span&gt;│   │   ├── Post/&lt;/span&gt;
&lt;span&gt;│   │   │   ├── _index.json&lt;/span&gt;
&lt;span&gt;│   │   │   ├── _index.mjs&lt;/span&gt;
&lt;span&gt;│   │   │   └── posts__hello-world.mdx.json&lt;/span&gt;
&lt;span&gt;│   │   ├── index.d.ts&lt;/span&gt;
&lt;span&gt;│   │   ├── index.mjs&lt;/span&gt;
&lt;span&gt;│   │   └── types.d.ts&lt;/span&gt;
&lt;span&gt;│   └── package.json&lt;/span&gt;
&lt;span&gt;├── content/&lt;/span&gt;
&lt;span&gt;│   └── posts/&lt;/span&gt;
&lt;span&gt;│       └── hello-world.mdx&lt;/span&gt;
&lt;span&gt;├── contentlayer.config.js&lt;/span&gt;
&lt;span&gt;├── next.config.js&lt;/span&gt;
&lt;span&gt;└── tsconfig.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Contentlayer converts the static MDX file (line 15) into a structured JSON file (line 8). All such JSON files are accessible through the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;allPosts&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; variable exported from &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;index.mjs&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; on line 7. In addition, it also generates type definitions (line 11) which helps Typescript understand the interface provided by the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;allPosts&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; import.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;json&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-line-numbers=&quot;&quot; data-language=&quot;json&quot; data-theme=&quot;github-dark-dimmed github-light&quot; data-line-numbers-max-digits=&quot;2&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;// .contentlayer/generated/Post/posts__hello-world.mdx.json&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;{&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;title&quot;&lt;/span&gt;: &quot;Hello World&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;published&quot;&lt;/span&gt;: &quot;2023-07-30T13:05:24.000Z&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;status&quot;&lt;/span&gt;: &quot;published&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;body&quot;&lt;/span&gt;: {
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;raw&quot;&lt;/span&gt;: &quot;\nHello world! This is my first post.\n&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;code&quot;&lt;/span&gt;: &quot;var Component=(()=&gt;{var sr=Object.create;...&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;_id&quot;&lt;/span&gt;: &quot;posts/hello-world.mdx&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;_raw&quot;&lt;/span&gt;: {
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;sourceFilePath&quot;&lt;/span&gt;: &quot;posts/hello-world.mdx&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;sourceFileName&quot;&lt;/span&gt;: &quot;hello-world.mdx&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;sourceFileDir&quot;&lt;/span&gt;: &quot;posts&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;contentType&quot;&lt;/span&gt;: &quot;mdx&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;flattenedPath&quot;&lt;/span&gt;: &quot;posts/hello-world&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;type&quot;&lt;/span&gt;: &quot;Post&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Below is the generated type definition for the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Post&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; document type -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;js&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;js&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;// .contentlayer/generated/types.d.ts&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;/** Document types */&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;export&lt;/span&gt; type Post = {
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;  /** File path relative to `contentDirPath` */&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;  _id&lt;/span&gt;: string
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;  _raw&lt;/span&gt;: Local.RawDocumentData
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;  type&lt;/span&gt;: &apos;Post&apos;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;  title&lt;/span&gt;: string
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;  published&lt;/span&gt;: string
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;  description&lt;/span&gt;?: string | undefined
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;  status&lt;/span&gt;: &apos;draft&apos; | &apos;published&apos;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;  /** MDX file body */&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;  body&lt;/span&gt;: MDX
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;computed-fields&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#computed-fields&quot;&gt;Computed Fields&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Once Contentlayer has generated the JSON files, the content is ready to consume on our pages. We will use Next.js&apos;s &lt;a href=&quot;https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes&quot;&gt;dynamic routes&lt;/a&gt; to render a single blog post. But before that, we must decide which unique value will be used for navigating the page. File path without the file extension is a standard approach used in the community (called a &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;slug&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;), but we currently don&apos;t have this value available easily.&lt;/p&gt;
&lt;p&gt;That&apos;s where Contentlayer&apos;s &lt;strong&gt;Computed Fields&lt;/strong&gt; come into the picture. It lets us compute new metadata from existing content. For example, it can be used to calculate the estimated reading time from the post content.&lt;/p&gt;
&lt;p&gt;To compute the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;slug&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; field, we need to modify the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;contentlayer.config.js&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; as follows -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;js&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-line-numbers=&quot;&quot; data-language=&quot;js&quot; data-theme=&quot;github-dark-dimmed github-light&quot; data-line-numbers-max-digits=&quot;2&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;export&lt;/span&gt; const Post = defineDocumentType(() =&gt; ({
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;  // The name of the document type&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  name: &lt;/span&gt;&quot;Post&quot;,
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;  // The type of the files to parse. &apos;md&apos; also works&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  contentType: &lt;/span&gt;&quot;mdx&quot;,
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;  // The path of the mdx files, relative to contentDirPath&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  filePathPattern: &lt;/span&gt;&quot;posts/*.mdx&quot;,
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;  // Fields present in the frontmatter of MDX file&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  fields: {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    title: { type: &lt;/span&gt;&quot;string&quot;, required: true },
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    published: { type: &lt;/span&gt;&quot;string&quot;, required: true },
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    description: { type: &lt;/span&gt;&quot;string&quot; },
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    status: {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      type: &lt;/span&gt;&quot;enum&quot;,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      options: [&lt;/span&gt;&quot;draft&quot;, &quot;published&quot;],
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      required: &lt;/span&gt;true,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  },&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  computedFields: {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    slug: {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      type: &lt;/span&gt;&quot;string&quot;,
&lt;span style=&quot;--shiki-dark:#DCBDFB;--shiki-light:#6F42C1&quot;&gt;      resolve&lt;/span&gt;: (doc) =&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        doc._raw.sourceFileName&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;          // hello-world.mdx =&gt; hello-world&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;          .&lt;/span&gt;replace(/\.mdx$/, &quot;&quot;),
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Once the JSONs are generated, you will notice a new field, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;slug&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, added to the post -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;json&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-line-numbers=&quot;&quot; data-language=&quot;json&quot; data-theme=&quot;github-dark-dimmed github-light&quot; data-line-numbers-max-digits=&quot;2&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;{&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;_id&quot;&lt;/span&gt;: &quot;posts/hello-world.mdx&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;title&quot;&lt;/span&gt;: &quot;Hello World&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;slug&quot;&lt;/span&gt;: &quot;hello-world&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;body&quot;&lt;/span&gt;: {
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;raw&quot;&lt;/span&gt;: &quot;\nHello world! This is my first post.\n&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;code&quot;&lt;/span&gt;: &quot;var Component=(()=&gt;{var sr=Object.create;...&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;  // [...]&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;We can do a lot more with the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;computedFields&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. We will explore this in more detail in future posts.&lt;/p&gt;
&lt;h1 id=&quot;lets-tie-it-all-together&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#lets-tie-it-all-together&quot;&gt;Let&apos;s tie it all together&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Let&apos;s build a dynamic article page with the information available. The aim is to show the nicely formatted markdown content whenever the user navigates to the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;&amp;#x3C;base_url&gt;/blog/hello-world&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; page on the blog.&lt;/p&gt;
&lt;p&gt;Create the following folder structure in the root of the project directory -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;txt&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-line-numbers=&quot;&quot; data-language=&quot;txt&quot; data-theme=&quot;github-dark-dimmed github-light&quot; data-line-numbers-max-digits=&quot;1&quot;&gt;&lt;span&gt;./&lt;/span&gt;
&lt;span&gt;└── app/&lt;/span&gt;
&lt;span&gt;    ├── blog/&lt;/span&gt;
&lt;span&gt;    │   ├── [slug]/&lt;/span&gt;
&lt;span&gt;    │   │   └── page.tsx&lt;/span&gt;
&lt;span&gt;    │   └── page.tsx&lt;/span&gt;
&lt;span&gt;    ├── layout.tsx&lt;/span&gt;
&lt;span&gt;    └── page.tsx&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;We will use the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;page.tsx&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; on line 5 to show a dynamic article page and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;page.tsx&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; on line 6 to display a list of all blog posts.&lt;/p&gt;
&lt;h2 id=&quot;blog-posts-list&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#blog-posts-list&quot;&gt;Blog Posts List&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Open up &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;./blog/page.tsx&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; in your code editor and add the following code -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;jsx&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-line-numbers=&quot;&quot; data-language=&quot;jsx&quot; data-theme=&quot;github-dark-dimmed github-light&quot; data-line-numbers-max-digits=&quot;2&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; Link from &quot;next/link&quot;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; { allPosts, Post } from &quot;contentlayer/generated&quot;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;export&lt;/span&gt; default function ListPage() {
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;  // sort posts based on &apos;published&apos; date&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  const&lt;/span&gt; posts: Post[] = allPosts.sort((a, b) =&gt; {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    return&lt;/span&gt; compareDesc(new Date(a.published), new Date(b.published))
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  })&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  return&lt;/span&gt; (
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;div&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      &amp;#x3C;&lt;/span&gt;h1&gt;Blog&amp;#x3C;/h1&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#24292E&quot;&gt;      {&lt;/span&gt;posts.map((post) =&gt; (
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        &amp;#x3C;&lt;/span&gt;div key={post.slug}&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;          &amp;#x3C;&lt;/span&gt;h2&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;            &amp;#x3C;&lt;/span&gt;Link href={`/blog/${post.slug}`}&gt;{post.title}&amp;#x3C;/Link&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;          &amp;#x3C;/&lt;/span&gt;h2&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        &amp;#x3C;/&lt;/span&gt;div&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      ))&lt;/span&gt;}
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;/&lt;/span&gt;div&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  )&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;article-page&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#article-page&quot;&gt;Article Page&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once we click on any entry on the blog list page, it takes us to the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/blog/&amp;#x3C;slug&gt;&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; page, where the content of the markdown file should be shown. Let&apos;s implement this functionality now -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;jsx&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-line-numbers=&quot;&quot; data-language=&quot;jsx&quot; data-theme=&quot;github-dark-dimmed github-light&quot; data-line-numbers-max-digits=&quot;2&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; { allPosts, Post } from &quot;contentlayer/generated&quot;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; { getMDXComponent } from &quot;next-contentlayer/hooks&quot;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;type&lt;/span&gt; Props = {
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;  params&lt;/span&gt;: { slug: string },
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;export&lt;/span&gt; default async function Page({ params }: Props) {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  const&lt;/span&gt; { slug } = params
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  const&lt;/span&gt; post: Post | undefined = allPosts.find((post) =&gt; post.slug === slug)
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  if&lt;/span&gt; (!post) {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    return&lt;/span&gt; &amp;#x3C;&gt;&amp;#x3C;/&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  }&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  const&lt;/span&gt; MdxContent = getMDXComponent(post.body.code)
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  return&lt;/span&gt; (
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;div&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      &amp;#x3C;&lt;/span&gt;h1&gt;{post.title}&amp;#x3C;/h1&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      &amp;#x3C;&lt;/span&gt;section&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        &amp;#x3C;&lt;/span&gt;MdxContent /&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      &amp;#x3C;/&lt;/span&gt;section&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;/&lt;/span&gt;div&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  )&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Contentlayer provides the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;getMDXComponent&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; hook, which can render the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;mdx&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; content on the page as HTML. Under the hood, our &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;mdx&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file was transformed by Contentlayer using a bundler into &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;JSX&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and cached in a JSON file, which was then picked up by Next.js to statically render using React.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Contentlayer greatly abstracts away the intricacies of using MDX content inside a Next.js project by doing most of the heavy lifting for us. It simplifies working with &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;unified&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;remark&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;rehype&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; ecosystems while providing interfaces to define a schema to our relatively freeform MDX content and type-safe data structures to access the transformed content.&lt;/p&gt;
&lt;p&gt;It is also possible to pass custom MDX components to the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;MdxContent&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to enable the re-mapping of standard markdown constructs to React components. We will dive deeper into it in future posts of the series.&lt;/p&gt;</content:encoded></item><item><title>Manali: Mountains and Memories</title><link>https://yashagarwal.in/notes/manali-mountains-and-memories/</link><guid isPermaLink="true">https://yashagarwal.in/notes/manali-mountains-and-memories/</guid><description>Relive a memorable trip to Manali, Himachal Pradesh, exploring the scenic mountains, travel planning insights, and unforgettable experiences.</description><pubDate>Sat, 22 Jul 2023 14:12:15 GMT</pubDate><content:encoded>&lt;p&gt;After our honeymoon got delayed for unfortunate reasons, we contemplated a short trip somewhere nearby. I had not visited the mountains until then, so I started looking for destinations in the Himalayas. Kashmir was the obvious choice, but I wanted to spend more than a few days in Kashmir which was not feasible then. Alternatives were to look for hill stations in Himachal and Uttarakhand. At last, we decided to go to Manali in Himachal Pradesh. We planned the trip for March 1, 2023, to March 4, 2023. The forecast was of rain, but still, we decided to go ahead.&lt;/p&gt;
&lt;h1 id=&quot;planning-stage&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#planning-stage&quot;&gt;Planning Stage&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;While planning the trip, I started looking for different options. One option was to book the tour through a tour operator in Jaipur, so the operator would take care of our commute, hotel, sightseeing and other activities. I also searched online websites like MakeMyTrip for packages. I found both these options to be expensive. Apart from that, one of my friends went to Manali last December. He also suggested not to opt for these two options. Ultimately, we decided to reach Chandigarh by train and then book a package.&lt;/p&gt;
&lt;p&gt;To reach Chandigarh, I booked Ajmer - Chandigarh Garib Rath Express for February 28. I had never travelled in a 3AC coach on Indian railways, so this was my first experience. I really liked it. The journey was smooth. They provide everything - blankets, bedsheets, pillows, pillow covers. However, I was slightly cautious about using these items at that time due to the prevailing COVID situation. Alas, the cold forced me to ignore my suspicions.&lt;/p&gt;
&lt;h1 id=&quot;jaipur-to-chandigarh&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#jaipur-to-chandigarh&quot;&gt;Jaipur to Chandigarh&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We reached Chandigarh early next morning at around 7 AM. One person showed us his travel agent&apos;s leaflet when we got off the train. I made a mistake here. Instead of inquiring there, I just went along with him. I blame the rain partly for this. It was showering mildly then, and I found it convenient to go with him. The guy took us to his travel agent&apos;s office, where we were explained the package. Although the tour package contained everything we read online, it had a few missing locations, which none of us noticed. Apart from this, we should&apos;ve asked about hotel details. Later we found out that the hotel given to us was far away from the main centre of Manali.&lt;/p&gt;
&lt;p&gt;When it came to negotiations, I fumbled. I should&apos;ve negotiated a bit more, but I didn&apos;t, and we settled on ₹18,000 for the package. Later I was told that the same tour could&apos;ve been done in even ₹14-15k.&lt;/p&gt;
&lt;p&gt;Another thing we didn&apos;t keep in mind was to negotiate the pricing of the hotel where we were going for refreshments before leaving for Manali. Ultimately the hotel owner took ₹400 for spending just one hour in a shady room.&lt;/p&gt;
&lt;h1 id=&quot;road-trip-to-manali&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#road-trip-to-manali&quot;&gt;Road Trip to Manali&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The road distance between Chandigarh and Manali is around 300 km. I usually hesitate about road travel due to motion sickness, but we had no choice. We started at around 9.30 AM from Chandigarh. After about an hour, we stopped at a roadside dhaba for breakfast.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/aaloo-paratha-on-our-way-to-manali.BAe5YCyH_Z1JFo1o.webp&quot; alt=&quot;A huge aaloo paratha&quot; title=&quot;Aaloo Paratha on our way to Manali&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;The driver then drove without stopping until we stopped for lunch at around 2.00 PM at Mayur Restaurant in Sundar Nagar. The restaurant was good, but we were not in good shape because of motion sickness.&lt;/p&gt;
&lt;p&gt;After having lunch, we drove for another hour before we reached the scenic Pandoh Dam. The view from here is beautiful, and the rush of air hitting your face makes you forget everything and enjoy the wonders of nature.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/the-majestic-beas-river.eDBvEhdx_Z1QaLBg.webp&quot; alt=&quot;The majestic Beas River&quot; title=&quot;The majestic Beas River&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4032&quot; height=&quot;3024&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/the-catchment-area-of-pandoh-dam.Cqvsqrfr_1tvVqt.webp&quot; alt=&quot;The catchment area of Pandoh Dam&quot; title=&quot;The catchment area of Pandoh Dam&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4032&quot; height=&quot;3024&quot;&gt;&lt;/p&gt;
&lt;p&gt;We spent nearly 45 minutes here before our driver reminded us that we may get late for Manali. So, with a heavy heart, we left the place and proceeded on our journey.&lt;/p&gt;
&lt;h1 id=&quot;the-river-rafting-in-kullu&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-river-rafting-in-kullu&quot;&gt;The River Rafting in Kullu&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Afterwards, we drove for another two hours before reaching Kullu. By this time, drizzles had started, and the roads of Kullu were wholly soaked with heavenly pours. In Kullu, we had options to do Paragliding and Rafting. As the weather was not conducive, we decided to go for rafting. Despite the rains, the river was not at its full strength, and nobody was along with us for rafting. So we and our guide boarded the boat and started our adventure. We booked a one-hour rafting tour for about a 10 km stretch of river. It cost us ₹6500 for the river rafting. This includes the safety gear and guide fee. We rented out waterproof clothing for another ₹200 per person. The guide offered us to shoot a video on his GoPro for ₹1500. Though slightly expensive, we agreed because we couldn&apos;t risk taking our mobile while on the boat. Despite the exorbitant charges, it was one of a kind experience.&lt;/p&gt;
&lt;p&gt;The guide fitted us with the safety gear - life jackets and helmets and then instructed us on handling the ride. The journey in the river started river, but soon we were hit by our first set of rapids. There was repeated turbulence beneath us, but the guide guided the boat carefully. Each time there was a strong wave, we were hit with cold water splashes from the Beas.&lt;/p&gt;
&lt;p&gt;We spent nearly an hour in the river, and by the time we reached the endpoint, we were drenched and shivering because of the icy water of the river. We immediately ran to a bonfire nearby and started giving ourselves the heat. It was so cold that I could put my foot in the fire without hurting myself. The vendor there offered us coffee. That tiny cup of coffee cost me ₹30, but it was invaluable then. The guide dropped us at our boarding point, where our driver was waiting. After payment and getting the videos on our phones, we started our journey again. After this, we were to stop only at our hotel.&lt;/p&gt;
&lt;h1 id=&quot;the-hotel&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-hotel&quot;&gt;The Hotel&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Our hotel, &lt;a href=&quot;https://goo.gl/maps/HAkDmQTxH9VicUD97&quot;&gt;The Snow Mount&lt;/a&gt;, was so remote that a tourist couldn&apos;t reach it without a car. We were very disappointed with our haphazardness while driving to this place. By the time we got there, it was almost 8.30 PM at night. We were starving, so we decided to order simple food. We were exhausted due to car travel, so after finishing dinner, we decided to call it a day.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/a-view-from-snow-mount.DToHzbcG_2sOsKP.webp&quot; alt=&quot;A view from Snow Mount&quot; title=&quot;A view from Snow Mount&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4032&quot; height=&quot;3024&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;solang-valley&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#solang-valley&quot;&gt;Solang Valley&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The following day, I woke up early and as soon as I went outside to check the balcony, all my frustration disappeared. The view was breathtakingly beautiful. We quickly got ready and came downstairs for breakfast. After having breakfast, our driver suggested that instead of going to the city sightseeing, we first go to Solang Valley because the weather forecast was gloomy for the next day. We agreed and proceeded to visit the Solang Valley. On the way, we stopped to book activities at Solang Valley. We booked zipline, mountain bike, Yak ride and tube ride. Looking back, I think we could&apos;ve done with zipline and Yak rides only as well. All these activities cost us ₹5000. The snow dresses cost another ₹500.&lt;/p&gt;
&lt;h2 id=&quot;ziplining&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#ziplining&quot;&gt;Ziplining&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We had never done ziplining, so it was a unique experience. Although the height of our zipline was not much, as a first experience, I am satisfied with it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/about-to-make-the-jump.Bqa7zTwL_1hg40V.webp&quot; alt=&quot;About to make the jump!&quot; title=&quot;About to make the jump!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;first-view-of-the-valley&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#first-view-of-the-valley&quot;&gt;First view of the valley&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After this, we went straight to the Solang Valley. This was my first view of the snow in real life, and I was totally awestruck by the vastness of it. We went in the low season, so a lot of snow had melted, but still, I could see the ocean of snow in front of me. What would be the scene after the heavy snowfalls we hear about in the news?&lt;/p&gt;
&lt;h2 id=&quot;mountain-bike&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#mountain-bike&quot;&gt;Mountain Bike&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When we finally reached the valley, the driver dropped us at the parking, from where the tour operator&apos;s mountain bike picked us up. The terrain was rocky, and we needed to go uphill. The ride was full of ups and downs, and we enjoyed it thoroughly. Was it a must-have? I don&apos;t think so. It is a good experience, but if you don&apos;t opt for it, you won&apos;t miss it. Later, I also got a chance to drive it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/riding-the-snow.s6vJoJH4_ZMg2LC.webp&quot; alt=&quot;Riding the snow&quot; title=&quot;Riding the snow&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;yak-ride&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#yak-ride&quot;&gt;Yak Ride&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After this, we were taken to Yak Ride. I saw a Yak for the first time and was instantly mesmerised by this animal. We were allowed to spend about 15 minutes on the animal.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/on-the-humble-beast.s5BiLciH_1dKEHV.webp&quot; alt=&quot;On the humble beast!&quot; title=&quot;On the humble beast!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3011&quot; height=&quot;3319&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;tube-ride&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#tube-ride&quot;&gt;Tube Ride&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After the Yak ride, we went for a tube ride. I don&apos;t know what is the point of this activity. People were being slid from the top of a cliff in a rubber tube on a snow trail. It took not more than 10 seconds from top to bottom, and that&apos;s it. You are done. This is the height of looting people. I fell for the same and immediately regretted it.&lt;/p&gt;
&lt;div&gt;&lt;video src=&quot;https://user-images.githubusercontent.com/13733968/253254179-3b909866-ea4a-486c-b8bf-d22e2ce4219a.mov&quot; data-canonical-src=&quot;https://user-images.githubusercontent.com/13733968/253254179-3b909866-ea4a-486c-b8bf-d22e2ce4219a.mov&quot; controls muted&gt;&lt;/video&gt;&lt;/div&gt;
&lt;h2 id=&quot;the-anjani-mahadev-temple&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-anjani-mahadev-temple&quot;&gt;The Anjani Mahadev Temple&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After this, our activities were over, and we were free to roam around on our own. Initially, we thought that was it. But then people were going further uphill. So we decided to go as well. We had to hire mules to reach the top as the slope was treacherously steep.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/the-beast-of-burden-or-a-burden-on-the-beast.BgnZb3vs_ZJ3snN.webp&quot; alt=&quot;The beast of burden or a burden on the beast?&quot; title=&quot;The beast of burden or a burden on the beast?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;Near our drop point, a stream of water comes down from the mountains. It is quite a picturesque location. We also collected some pebbles from here while on our way back later.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/nature-we-and-romance.Cpk7h-k6_1UJXJl.webp&quot; alt=&quot;Nature, we and romance ❤️&quot; title=&quot;Nature, we and romance ❤️&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;So, on the hilltop, there is the Anjani Mahadev Temple. A few sadhus live and worship the temple deities there. We went inside the temple, prayed and came outside. There was a great rush of people here. Hence, the sadhus repeatedly got angry about people&apos;s negligence of the temple decorum.&lt;/p&gt;
&lt;p&gt;Going even further, a waterfall on a hilltop continuously showers a Shiva Linga inside a well. At that time, the way to the hill was totally covered in snow, so it was pretty dangerous to climb to the top. But we saw a few Malayali (I keep finding them even now!) boys doing it, and with their help, we decided to do it as well. They had managed to get a few sticks for support. We borrowed two wooden sticks from them and started our upward trek. Once we reached the top, it was time to slide down. We climbed to the top to do this. However, it was pretty dangerous. One wrong step and you will hurt yourself badly. We reached the bottom, however, with some bruises on my palms.&lt;/p&gt;
&lt;p&gt;When we reached down, we saw a massive snow plaque with the date 2.3.23 written on it. We decided to talk to the vendor and get our photos clicked. It was a paid service, but totally worth it because we completed three months of our wedding on this day. And clicking pictures here made this day memorable.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/love-is-in-the-air.wI6N-enr_Hivt1.webp&quot; alt=&quot;Love is in the air!&quot; title=&quot;Love is in the air!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;After this, we hired another mule and began our descent. Once we reached the parking spot, we undressed ourselves and decided to bid farewell to Solang Valley. It was a day of unique experiences and many firsts.&lt;/p&gt;
&lt;h1 id=&quot;nehru-kund&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#nehru-kund&quot;&gt;Nehru Kund&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;On our way to Mall Road, we stopped at Nehru Kund. As per our driver, it is a freshwater stream whose source is unknown. It was not crowded at all. The water was coming from a plastic pipe. I think this place doesn&apos;t need more than a passing glance.&lt;/p&gt;
&lt;h1 id=&quot;van-vihar&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#van-vihar&quot;&gt;Van Vihar&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;After this, our driver dropped us at Mall Road to roam and asked us to be ready for pickup by 8.30 PM. So, we had around 3-4 hours to wander around. So we decided to take a round of Van Vihar. It is on the main Mall Road, so it wasn&apos;t difficult to find. This is a park adorned with sky-touching deodar trees. It is good enough to spend 1-2 hours amidst the tree away from the noise of the Mall road. After this, we shopped and had dinner at a Punjabi dhaba on Mall Road. The food was average.&lt;/p&gt;
&lt;h1 id=&quot;city-sightseeing&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#city-sightseeing&quot;&gt;City Sightseeing&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We planned a tour of famous tourist attractions in and around Manali the following day. We visited Hadimba Devi Temple, Clubhouse, Manu Temple, and Tibetan Buddhist Monastery. People also go to Vashisth Bath, Nagar Castle and Rohtang Pass, but our tour operator didn&apos;t include these in our plan. We were careless while booking our package and had to pay the price during our entire tour.&lt;/p&gt;
&lt;h2 id=&quot;hidimba-devi-temple&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#hidimba-devi-temple&quot;&gt;Hidimba Devi Temple&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First, we went to Hidimba Devi Temple, a temple dedicated to Hidimba, the wife of the Bhima, the second of the Pandava brothers from Mahabharata. It is a 500-year-old temple built at the foot of the Himalayas.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/hidimba-devi-temple-from-back.DqCNL6dG_Z2kckxe.webp&quot; alt=&quot;Hidimba Devi Temple from back&quot; title=&quot;Hidimba Devi Temple from back&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;After getting a darshan of the Devi, we strolled in the nearby Dhungiri Van Vihar. It is a lovely little forest covered with Cedar trees. It also has a tiny water pond.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/we-among-the-trees.BDfZ0nFG_1BMcPB.webp&quot; alt=&quot;We among the trees 🌳&quot; title=&quot;We among the trees 🌳&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;We also visited Ghatotkacha Temple nearby. Locals have also built a temple dedicated to the grandson of Hidimba, Barbarika, at around one km distance. We also decided to visit that temple.&lt;/p&gt;
&lt;h2 id=&quot;clubhouse&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#clubhouse&quot;&gt;Clubhouse&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After the Hidimba temple, we went to the City Clubhouse. There is hardly anything to do at this place. The whole place is a sham.&lt;/p&gt;

&lt;p&gt;One can go near the river to take pictures or just sit on the stones in the middle of the river. On the river bank, ziplining activities are available, but we didn&apos;t opt for them. There are some souvenir shops, but I suggest not buying from them. Instead, buy from Mall Road. You will have a good chance of bargaining there.&lt;/p&gt;
&lt;h2 id=&quot;manu-temple&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#manu-temple&quot;&gt;Manu Temple&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Next, we went to Manu Temple, which is about 2 km away from the Clubhouse. The journey was uphill, and soon we regretted our decision to walk. Alas, we managed to reach the temple. Even here, there is nothing to see. According to Hindu scriptures, it is said to be the only temple dedicated to Manu, the first human.&lt;/p&gt;
&lt;p&gt;After this, we came back to Mall Road. The driver dropped us there just like the last day and asked us to call him when we were ready to return to the hotel.&lt;/p&gt;
&lt;h2 id=&quot;tibetan-buddhist-monastery&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#tibetan-buddhist-monastery&quot;&gt;Tibetan Buddhist Monastery&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After arriving at Mall Road, we went to the Tibetan Buddhist Monastery, which is very near the Van Vihar. When we reached there, it was very crowded, with waves of people coming in and out of the monastery as if it were a picnic spot. But, how can I complain when I also went there for sightseeing. It is a nicely maintained place. However, everything is written in what I suspect is the Tibetan language, so even if I wanted to understand the context behind the statues and iconography, I couldn&apos;t.&lt;/p&gt;
&lt;p&gt;We ate something interesting here - Laping, a Tibetan speciality filled with noodles and Paneer, and served with red chilli chutney and soy sauce. This was very spicy, and I was left with teary eyes after eating this. To save myself, I had to run to get Gulabjamuns sold by street vendors near Van Vihar. Apart from that, I really loved this dish. We also interacted with the old man who served in the Indian army as a sepoy 30 years back and now sells these lappings to pass his time.&lt;/p&gt;
&lt;h1 id=&quot;shopping&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#shopping&quot;&gt;Shopping&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;After visiting the monastery, we were done with seeing all the attractions mentioned in our itinerary. So, we decided to do some shopping. Given the experience of the past two days, we were determined to only buy something with good haggling. We spent nearly 2 hours roaming the area and purchasing souvenirs for friends and family. Later in the night, we went to La Pino&apos;z Pizza on Mall Road for a quick dinner.&lt;/p&gt;
&lt;p&gt;After dinner, we were roaming on Mall Road, and a random man came near me and asked me - “Sir, joint loge kya?”. I was stunned and immediately said no and left the scene. I hope he came to me randomly and not because of my appearance 🤣.&lt;/p&gt;
&lt;p&gt;After this, it started drizzling slowly, so we called the driver and returned to the hotel.&lt;/p&gt;
&lt;h1 id=&quot;back-to-chandigarh&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#back-to-chandigarh&quot;&gt;Back to Chandigarh&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We decided to leave early the next day as our train to Jaipur was scheduled for 7.30 PM. Earlier, we had planned to go Paragliding in Kullu on our way back to Chandigarh. However, we were so exhausted that we decided to do in future.&lt;/p&gt;
&lt;p&gt;While travelling, we stopped at Shri Ram Shawls in Kullu to buy shawls for our family. Our driver took us here, saying this is the best outlet to buy Himachali shawls in Kullu. We liked the quality of the products there, but there was no bargaining allowed. We will only learn about the quality in the next winter season. We also stopped at a roadside vendor to buy some local dried fruit items, which tasted good.&lt;/p&gt;
&lt;p&gt;After this, we didn&apos;t stop at any other place apart from for lunch at Annapurna Bhojnalaya in Sundar Nagar. However, due to unforeseen circumstances, we still missed our train. First, we had a minor accident near Mandi. Then one of the tyres of our car got punctured near the Haryana border. Once the driver got it fixed, we were stuck in a long traffic jam. All these incidents combined, and we missed our train by one hour. So the next thing I could do was to immediately book bus tickets for both of us. We booked sleeper class tickets in an AC bus as we both were exhausted and wanted to sleep. The driver dropped us at the bus pickup point in Chandigarh and bid us goodbye. After we boarded the bus, the next thing I saw was the Narayan Singh Circle in Jaipur.&lt;/p&gt;
&lt;h1 id=&quot;lessons&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#lessons&quot;&gt;Lessons&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This was my first trip with my wife and the first trip where no friends were involved. It taught me the importance of bargaining on any trip. I should&apos;ve tried to bargain a lot more with the tour agent. I lost a significant ₹2-3k there. Later I was cautious, but the street vendors tried to dupe us. But thankfully, we managed to negotiate the prices a bit on almost all occasions.&lt;/p&gt;
&lt;p&gt;Also, I needed to be more careful while discussing the tour details with the agent. If I had paid more attention, I could&apos;ve persuaded him to add a few destinations to the sightseeing package and extracted more value for my money.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This was my first proper trip with my wife. Our honeymoon got delayed, but we didn&apos;t delay too much either. This was a short trip to a place I always wanted to visit. I have always been attracted to the grandeur of the Himalayas, and seeing them from so near was a fantastic experience.&lt;/p&gt;</content:encoded></item><item><title>How I built a blog with Next.js</title><link>https://yashagarwal.in/notes/how-i-built-a-blog-with-nextjs/</link><guid isPermaLink="true">https://yashagarwal.in/notes/how-i-built-a-blog-with-nextjs/</guid><description>Discover the journey of building a modern blog with Next.js, from migrating off Hugo to overcoming challenges in content management.</description><pubDate>Fri, 14 Jul 2023 14:55:24 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/website-screenshot.DMODa2Bo_Z200lNa.webp&quot; alt=&quot;A screenshot of new design&quot; title=&quot;A screenshot of new design&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1616&quot; height=&quot;1400&quot;&gt;&lt;/p&gt;
&lt;p&gt;Hugo, the fastest static site generator of the world, served me well for almost 7 years. I made several iterations to my blog in these seven years. However, in these years, the web has advanced by leaps and bounds, and my aspirations have grown by an equal magnitude, if not more. I began to desire a lot more from my blog. I wanted a new design using the latest tools and real-time data fetching using APIs. Above everything else, my zeal to keep learning kept me dissatisfied with Hugo. Hugo made some improvements to incorporate &lt;a href=&quot;https://gohugo.io/hugo-pipes/js/&quot;&gt;JS&lt;/a&gt;, but I neither had time to understand these nor was I convinced about it. Perhaps, I knew Hugo so well after working on it for so long, that the idea of transitioning away from it felt intimidating.&lt;/p&gt;
&lt;p&gt;At last, I decided to start looking away from Hugo in 2021. I was fixated on migrating to a JavaScript-based SSG for almost two years. I finally tried my hands on &lt;a href=&quot;https://github.com/yashhere/yashagarwal.in-v2-failed&quot;&gt;Gatsby&lt;/a&gt; in 2022, but I failed spectacularly — perhaps because I was in my courtship period then, I couldn&apos;t devote enough time to learn the intricacies of a new framework.&lt;/p&gt;
&lt;p&gt;After that, I shelved the idea due to lack of time. However, the complexity of writing in markdown kept preventing me from writing continuously, which meant there was almost zero activity on my blog.&lt;/p&gt;
&lt;h1 id=&quot;why-now&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#why-now&quot;&gt;Why now?&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;About two months ago, while casually browsing Twitter, I came across a tweet mentioning the use of Notion as a CMS for a Next.js blog, all thanks to the newly released Notion API. As soon as I read the post, I knew I had to try it. The reason was simple - it would help me solve my most prominent &lt;a href=&quot;https://yashagarwal.in/notes/2021-a-bullish-year#blogging-and-writing&quot;&gt;problem&lt;/a&gt; of the past few years - the separation of content from the code. I was long looking for a way to solve this issue. Notion&apos;s editor is intuitive, full of features, easy to use and available on all platforms I use regularly.&lt;/p&gt;
&lt;h1 id=&quot;roadblocks&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#roadblocks&quot;&gt;Roadblocks&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;It was time to start brushing my web development skills again. React is in trend currently, and Next.js is a popular framework built upon it. I had also heard about TailwindCSS and how it is used to create almost every website nowadays. So I decided to use these two to build my website.&lt;/p&gt;
&lt;p&gt;However, it was more complicated than I thought it would be. My lack of knowledge of TypeScript and TailwindCSS meant I struggled to get basic functionality working for almost one month. Fetching and integrating Notion data using its API proved even more tedious. The state of Notion API, the performance issues, and the community support are not in ideal shape for an absolute JS beginner like me. I found &lt;a href=&quot;https://www.contentlayer.dev/&quot;&gt;Contentlayer&lt;/a&gt;, which is a translation layer to convert the content into JSON format suitable for use in code. It has a plugin to convert Notion data to JSON. However, this plugin is in the alpha stage, and has several limitations.&lt;/p&gt;
&lt;p&gt;As I struggled with adding Notion support, I made a &lt;em&gt;tough&lt;/em&gt; decision. I decided to drop the idea of using Notion as CMS for the time being and use the MDX for storing the content while simultaneously honing my design and JS skills and return to Notion once I am more confident about my skills. To reduce the complexity, I have decided not to use any custom React component in my MDX files. I will still write in Notion and once the article is ready, I will copy-paste it to an MDX file and commit the file to Git. A bit of manual setup is involved here, but I am okay with it. This setup would&apos;ve worked with my Hugo blog, too, but over time, I had integrated so many &lt;a href=&quot;https://github.com/yashhere/tufte.yashagarwal.in/blob/source/content/posts/2019-06-26-travelogue-Chikmagalur/index.md?plain=1#L24&quot;&gt;custom&lt;/a&gt; shortcodes that the markdown files no longer looked like markdown. This time, I am intentionally sticking to the standard markdown syntax to simplify any future migration.&lt;/p&gt;
&lt;h1 id=&quot;base-design&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#base-design&quot;&gt;Base Design&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I found it challenging to adapt TailwindCSS, partly because I was returning to CSS after a long time and partly because I have had problems understanding technologies that tend to abstract away the complexities of underlying concepts. I still remember my struggles with understanding Python purely because I got so habitual to coding in the C language that the built-in methods provided by the Python language confused me.&lt;/p&gt;
&lt;p&gt;As I struggled with Tailwind and coding in raw CSS was not a good option with Next.js, I decided to look for a portfolio that could act as a base for my changes. The &lt;a href=&quot;https://www.emmacampbell.dev/&quot;&gt;portfolio&lt;/a&gt; of Emma Campbell was the right fit for my requirements. It was built with Next.js App Router and TailwindCSS. It had all the features I required (except a few, like Table of Contents). Above all, I could understand the codebase, so it was easy to dive in and make changes to the design.&lt;/p&gt;
&lt;h1 id=&quot;features&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#features&quot;&gt;Features&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Some functionality was already present in Emma&apos;s codebase -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Contentlayer integration&lt;/li&gt;
&lt;li&gt;Views Counter using Kysely and Planetscale&lt;/li&gt;
&lt;li&gt;Code highlighting&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I added/improved several other features to the codebase -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;MathJax support&lt;/li&gt;
&lt;li&gt;RSS feed and sitemap generation&lt;/li&gt;
&lt;li&gt;Dark mode support&lt;/li&gt;
&lt;li&gt;Giscus comments&lt;/li&gt;
&lt;li&gt;Umami and Cloudflare analytics&lt;/li&gt;
&lt;li&gt;Simplified code highlighting implementation&lt;/li&gt;
&lt;li&gt;OpenGraph image generation&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I plan to add following features to this blog in future -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Table of contents&lt;/li&gt;
&lt;li&gt;Image component improvements
&lt;ol&gt;
&lt;li&gt;Caption support&lt;/li&gt;
&lt;li&gt;Gallery and “Click to Expand” feature&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Tooltips&lt;/li&gt;
&lt;li&gt;404/500 pages&lt;/li&gt;
&lt;li&gt;Change OG image generation implementation&lt;/li&gt;
&lt;li&gt;Add a dark mode toggle button&lt;/li&gt;
&lt;li&gt;Full text search on blog page&lt;/li&gt;
&lt;li&gt;Move to Redis to reduce latencies&lt;/li&gt;
&lt;li&gt;Proper error handling in components&lt;/li&gt;
&lt;li&gt;IndieWeb&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;and many more …&lt;/p&gt;
&lt;h1 id=&quot;inspirations&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#inspirations&quot;&gt;Inspirations&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This blog was only possible with many amazing people open-sourcing their blogs. I took inspiration from their design and sometimes picked up their code. Here is a brief and incomplete list of blogs that influenced me a lot - &lt;a href=&quot;https://www.emmacampbell.dev/&quot;&gt;Emma Campbell&lt;/a&gt;, &lt;a href=&quot;https://leerob.io/&quot;&gt;Lee Robinson&lt;/a&gt;, &lt;a href=&quot;https://delba.dev/&quot;&gt;Delba de Oliveira&lt;/a&gt;, &lt;a href=&quot;https://anishde.dev/&quot;&gt;Anish De&lt;/a&gt;, and &lt;a href=&quot;https://www.joshwcomeau.com/&quot;&gt;Josh W Comeau&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;coming-next&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#coming-next&quot;&gt;Coming Next&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I plan to write separate articles explaining how I implemented every feature mentioned above. Stay tuned!&lt;/p&gt;</content:encoded></item><item><title>2022 - The Year of Plentiful</title><link>https://yashagarwal.in/notes/2022-the-year-of-plentiful/</link><guid isPermaLink="true">https://yashagarwal.in/notes/2022-the-year-of-plentiful/</guid><description>A comprehensive 2022 year in review, reflecting on personal growth, health, career decisions, and future aspirations amidst life&apos;s challenges.</description><pubDate>Sat, 31 Dec 2022 13:25:03 GMT</pubDate><content:encoded>&lt;p&gt;2022 is about to end. It is that time when I say goodbye to one more year in my
life and welcome a new one. 2022 was a hectic year for me. Many of my decisions
this year will have rippling effects for years to come. But there was also a
good realization that I must take action; sitting idle won&apos;t help.&lt;/p&gt;
&lt;p&gt;As always, I have divided this review into those areas of my life where I have
been putting more focus throughout the year.&lt;/p&gt;
&lt;h1 id=&quot;health&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#health&quot;&gt;Health&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&quot;fitness&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#fitness&quot;&gt;Fitness&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I wish I had put more focus on my fitness this year. My sedentary lifestyle may
put me at many health risks in years to come. My activity levels have been
abysmally poor for most of the year. A big reason behind this was my busyness in
other parts of my life. 2022 was an amalgamation of stress, fear, anxiety,
surprises, gratitude, and happiness. Fitness took a back seat due to the quick
turnaround of events throughout the year. Early in the year, I continued with
Yoga. However, I was a lot more irregular this year because I wanted to gain
muscles while keeping my weight constant. So, I decided to join a gym in the
second half of the year to focus on muscle building. However, due to the stress
of wedding preparations, I couldn&apos;t find the motivation to continue beyond two
months. There was one positive, though - whenever I committed to working out, I
could notice a boost of confidence spurting inside me. Unfortunately, I found it
challenging to maintain this motivation for long.&lt;/p&gt;
&lt;p&gt;I didn&apos;t have to suffer from any significant illness this year. I occasionally
suffered from slight back pain, which can be attributed to my poor posture.
Doing Yoga keeps my back in shape, but whenever I stop doing Yoga, I start
feeling the pinch again in one or two months. This factor alone makes me realize
the importance of keeping my body active.&lt;/p&gt;
&lt;h2 id=&quot;sleep&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#sleep&quot;&gt;Sleep&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I managed to sleep around seven hours each day throughout the year. However,
this data doesn&apos;t include my afternoon naps, so my daily sleep duration is
undoubtedly higher than 7 hours. Sleeping in the afternoons has become a habit
that I never intended to develop. But now, it has become a permanent fixture in
my life. In 2023, I plan to keep my tendency to sleep in the afternoon in
control, but that will require sleeping enough at night, without which all my
efforts will remain useless.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/average_sleep_duration.BrqVcuar_BrOv1.webp&quot; alt=&quot;Sleeping in 2022&quot; title=&quot;How much I slept in 2022?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1532&quot; height=&quot;964&quot;&gt;&lt;/p&gt;
&lt;p&gt;I slept the least in June, which is surprising. I was expecting it to be in
July, August, and September when I was in the midst of my courtship period.&lt;/p&gt;
&lt;p&gt;I would have liked to put a graph showing my sleep and wake-up times as well,
but my graph plotting skills require some polishing, so for now, I will stop
here. Someday, I would like to analyze that data as well.&lt;/p&gt;
&lt;h1 id=&quot;career&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#career&quot;&gt;Career&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&quot;netskope&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#netskope&quot;&gt;Netskope&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Joining Netskope was a good decision for my career. While I learned a lot at
Cisco, my experience at Netskope has been different. This year, after seeing the
turbulent market conditions, I kept on wondering if joining Netskope was a
financially prudent decision. If I keep this fact aside, my experience at
Netskope has been good.&lt;/p&gt;
&lt;h2 id=&quot;learning&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#learning&quot;&gt;Learning&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have not been able to keep up with emerging technologies in the last two-three
years. While my basics are solid, I should invest some time in learning new
trends to stay relevant and employable in the future. The tech industry can be
fierce at times. With all the turmoil in the world, it becomes even more
important to keep myself updated. For the last four years, I have been lacking
in learning new things (irrespective of their connection to my work). That may
have put me behind my peers by a few years. Whenever I see my peers racing ahead
of me, I feel disappointed. I know that becoming part of this rat race will only
give me grief, but as a human, I am not immune to these emotions. However, I am
very well aware that taking action is the only way to come back on track.&lt;/p&gt;
&lt;h2 id=&quot;future&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#future&quot;&gt;Future&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For the first time in the last three years, I feel clarity in my thoughts about
my future direction, which may be a good sign. Going into 2023, this clarity can
prove miraculous for my career and personal life. I hope it is the case.&lt;/p&gt;
&lt;h1 id=&quot;writing&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#writing&quot;&gt;Writing&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-problem&quot;&gt;The Problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Writing regularly was one of my primary goals this year. For the last couple of
years, I have been struggling with some mental block when it comes to writing.
It turns out that the problem was the lack of content. I either did not have
anything to write about, or needed to try harder to gather the material, or
procrastinated. I wrote less this year too, but I could get into the flow
whenever I wanted to.&lt;/p&gt;
&lt;h2 id=&quot;journaling&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#journaling&quot;&gt;Journaling&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Blogging was not a priority this year. However, journaling has proven to be a
wonderful experience for me this year. More so, it gave me a window into my
thought process when making the most critical decision of my life - whether to
marry or not. I wrote extensively around that time about what I was thinking,
what I liked in her, and what I didn&apos;t. When I reread those entries, it
immediately brings a smile to my face. Such has been the impact of journaling on
me. I plan to write many more journal entries next year. I hope these new
entries will also bring a smile to my face in the distant future.&lt;/p&gt;
&lt;h2 id=&quot;hobby&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#hobby&quot;&gt;Hobby&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have a long-term wish to start a newsletter and grow my audience, but I wonder
if I am ready to put in the effort required for this task at this moment. Also,
I need to be more confident about whether I have good content/topic to write
about. Since I still hesitate to share my blog posts on social media, starting
and growing a newsletter will be an uphill task.&lt;/p&gt;
&lt;p&gt;Getting committed this year meant that I finally had some inspiration to engage
with creative writing. And I thoroughly enjoyed writing for someone else. In the
last seven years since I started writing, I have never tried to write in Hindi.
But after doing it this year, I realized that I enjoy writing in Hindi. I plan
to continue this (even if sporadically) in 2023.&lt;/p&gt;
&lt;h1 id=&quot;reading&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#reading&quot;&gt;Reading&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&quot;the-failure&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-failure&quot;&gt;The failure&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have a feeling of disappointment while writing this section. I decided to read
24 books this year. I am ending it without reading a single book. Throughout the
year, I could not make up my mind about reading. A significant reason behind
this was the double thoughts in my mind about the objective for which I was
reading and whether I could retain whatever I was reading. I found myself
struggling to come to terms with the fact that no matter what I do, I will never
be able to recall everything I read. This realization was the root cause behind
my disillusion with reading. Unfortunately, I still need to find a definite
answer to this dilemma. However, I can still restart my reading journey with
fiction books, as I don&apos;t see the need to remember such books.&lt;/p&gt;
&lt;h2 id=&quot;but&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#but&quot;&gt;But…&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Having said this, it is not that I didn&apos;t read anything at all. I managed to
read the first three modules of Zerodha&apos;s varsity content. These modules are
such a valuable source to learn about the markets. I thoroughly enjoyed reading
them. Unfortunately, at least this year, I didn&apos;t use the knowledge gathered. To
start with the stock market again, I may have to reread the modules to recall
the concepts (this is one example of the issues I mentioned in the previous
paragraph).&lt;/p&gt;
&lt;h1 id=&quot;media-consumption&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#media-consumption&quot;&gt;Media Consumption&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&quot;bingeing&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#bingeing&quot;&gt;Bingeing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One side effect of not reading enough books was that my mind tried to find other
avenues to pass the time. In the first half of the year, I took refuge in movies
and TV series to relieve myself from day-to-day life. I watched 22 films and
three web series in the year&apos;s first half. Before getting married, I watched
only two movies between July and November. After getting married, in December, I
watched five movies.&lt;/p&gt;











































































































































































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;strong&gt;Name&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;Type&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;Month&lt;/strong&gt;&lt;/th&gt;&lt;th&gt;&lt;strong&gt;Rating&lt;/strong&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Loki&lt;/td&gt;&lt;td&gt;Show&lt;/td&gt;&lt;td&gt;January&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Eternals&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;January&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Pushpa: The Rise - Part 1&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;January&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;What If…&lt;/td&gt;&lt;td&gt;Show&lt;/td&gt;&lt;td&gt;January&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Kingsman: The Golden Circle&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;February&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;The King&apos;s Man&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;February&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Mortal Kombat&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;February&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Rudra&lt;/td&gt;&lt;td&gt;Show&lt;/td&gt;&lt;td&gt;March&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Spider-Man: No Way Home&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;March&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Bell Bottom&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;March&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Wanted&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;March&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Housefull 4&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;March&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Dasvi&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;April&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;National Treasure&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;April&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Badhaai Do&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;April&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;National Treasure: Book of Secrets&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;April&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;The Batman&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;April&lt;/td&gt;&lt;td&gt;9&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Pirates of the Caribbean: The Curse of the Black Pearl&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;May&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Pirates of the Caribbean: Dead Man&apos;s Chest&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;May&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;The Lost City&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;May&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;The Chronicles of Narnia: The Lion, the Witch and the Wardrobe&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;May&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;The Chronicles of Narnia: Prince Caspian&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;May&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;The Chronicles of Narnia: The Voyage of the Dawn Treader&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;May&lt;/td&gt;&lt;td&gt;9&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;K.G.F: Chapter 2&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;May&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Doctor Strange in the Multiverse of Madness&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;June&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Brahmāstra Part One: Shiva&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;September&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Thor: Love and Thunder&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;October&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Doctor G&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;December&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Cirkus&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;December&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Govinda Naam Mera&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;December&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Encanto&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;December&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;The Dictator&lt;/td&gt;&lt;td&gt;Movie&lt;/td&gt;&lt;td&gt;December&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;social-media&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#social-media&quot;&gt;Social Media&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I was in control of my social media usage in the first half of the year, but
Instagram caught me off guard after that. I have never been a fan of Instagram,
but this year, circumstances forced me to get into the rabbit hole. Currently, I
have managed to control my Instagram usage. Still, I need to keep my eyes open
to avoid any addiction.&lt;/p&gt;
&lt;h2 id=&quot;phone&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#phone&quot;&gt;Phone&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I don&apos;t have my phone usage data, but I am sure it has skyrocketed this year.
Since July, I have managed to use my phone for more than 6 hours every day on a
routine basis. I must figure out how to reduce this usage and focus on more
important things.&lt;/p&gt;
&lt;h1 id=&quot;family&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#family&quot;&gt;Family&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&quot;back-to-office&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#back-to-office&quot;&gt;Back to Office&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Since the beginning of the pandemic, I have been staying with my family. It has
been three years, and with each passing day, I feel uncomfortable even thinking
about moving back to Bengaluru. With the feeling of belongingness combined with
the mess that Bengaluru is in, I find myself resisting moving back to Bengaluru,
at least in the near future. My employer supports remote work, which gives me
hope that I can spend a few more months here in Jaipur. Staying in Jaipur has
obvious monetary benefits, but I see long-term hindrances in career growth. I
may have to find a middle path to avoid stagnating in my career and satisfy my
emotional cravings towards my family.&lt;/p&gt;
&lt;h2 id=&quot;fam&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#fam&quot;&gt;Fam&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On the family front, this year has been incredible. Several long-term wishes of
my family got fulfilled this year. My mother came back home after a successful
recovery from a severe ailment. We shifted to a new house. I got married. My
brother got a government job. What else could I have asked for?&lt;/p&gt;
&lt;h2 id=&quot;vishi&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#vishi&quot;&gt;Vishi&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As the latest entrant into my family, she has been a welcome addition. When 2022
started, the idea of getting married was completely absent from my mind. There
were other &lt;em&gt;more&lt;/em&gt; &lt;em&gt;important&lt;/em&gt; stuff in my life that required immediate
attention. But life had its plans. And I am glad that life had its way. Though I
was not rooting to get married, I found a person with whom my thoughts match. I
have not been a people-friendly person in my personal life, so it will take some
time to adjust to another person&apos;s presence. Still, the way we have spent the
last five months together, this will be a fun journey together.&lt;/p&gt;
&lt;h1 id=&quot;what-in-2023&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#what-in-2023&quot;&gt;What in 2023?&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;My experience says I could improve following up with my new year&apos;s resolutions.
However, that is not going to stop me from resoluting some more goals this year
as well. Even if I don&apos;t achieve any of these, they will linger around in the
back of my mind and remind me to take at least one step toward them.&lt;/p&gt;
&lt;h2 id=&quot;fitness-1&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#fitness-1&quot;&gt;Fitness&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I don&apos;t know of any method to quantify my fitness progress, but I aim to keep my
weight under 65 kgs while transferring some of my weight from fat to muscles.&lt;/p&gt;
&lt;h2 id=&quot;reading-1&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#reading-1&quot;&gt;Reading&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I have decided to read &lt;strong&gt;at least&lt;/strong&gt; 24 books (2 books per month) this year. A
combination of fiction, non-fiction, Hindi, and technical books would be ideal
and help me avoid the sudden lack of interest. You can track my progress
&lt;a href=&quot;https://www.goodreads.com/user/show/63354397-yash&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;writing-1&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#writing-1&quot;&gt;Writing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some journal entries, &lt;a href=&quot;https://www.futureme.org/&quot;&gt;FutureMe&lt;/a&gt; letters, and a few
blog posts should be enough for this year. I am writing more than ever
privately, but as a side effect, public writing has taken a back seat for now. I
will write on this blog whenever I have something important to share.&lt;/p&gt;
&lt;p&gt;I enjoyed journaling in 2022, so this is also high on my priority list for 2023.
I intend to write only sometimes, but doing it once in a while - on important
events of my life - should be doable.&lt;/p&gt;
&lt;h2 id=&quot;travel&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#travel&quot;&gt;Travel&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that I have a partner-in-crime, I plan to travel extensively (while keeping
financial and professional commitments in mind). The resurge of COVID is
threatening to spoil one of my trips early next year, so I also need to keep an
eye on that. However, I will travel as and when possible. Expect some travelogue
posts on this blog in the near future.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;2022 was a good year for me. I achieved many goals this year. After a long time,
I have some clarity in my mind about my future course of action. I hope to
execute some (or all) of my plans in 2023.&lt;/p&gt;
&lt;p&gt;This year taught me a vital lesson - every time you plan something, there will
be a lot of apprehensions. All it takes to proceed further is to take one step.
Everything else automatically falls into place.&lt;/p&gt;
&lt;p&gt;Thank you, 2022, for this critical lesson. Adios, I will never forget you for
bringing so many new memories into my life.&lt;/p&gt;
&lt;p&gt;And welcome to you, 2023!!!&lt;/p&gt;</content:encoded></item><item><title>I Got Engaged 💍</title><link>https://yashagarwal.in/notes/i-got-engaged/</link><guid isPermaLink="true">https://yashagarwal.in/notes/i-got-engaged/</guid><description>The author shares the surprising journey to engagement, reflecting on new emotions and the personal reasons behind this life-changing decision.</description><pubDate>Sat, 06 Aug 2022 12:05:24 GMT</pubDate><content:encoded>&lt;p&gt;Life sometimes takes such unexpected turns that we humans can only stand still
and wonder. That&apos;s what happened to me. Just two months back, I was urging my
father to stop talking to me about my marriage plans, and here I am today,
announcing my engagement. It is how the sequence of events has been in my life
in the last two months. However, I am not at all troubled with all these sudden
turns and twists.&lt;/p&gt;
&lt;p&gt;Coming to the topic of the discussion, the name of my fiancée is Vishakha. Our
roka-cum-engagement ceremony took place on 30th of July. We exchanged rings
before a small family gathering and had our first pooja together. Now, we are
officially in our courtship period. We both belong to slightly different
educational backgrounds and academic interests. However, that doesn&apos;t seem to be
a barrier between us, and we share many views about life, family, society, and
other things in general.&lt;/p&gt;
&lt;p&gt;I have been timid in talking to strangers, but right from our first meeting, I
struck a strange connection with her. Our first meeting lasted for around one
and a half hours, which astonished our families, given that she and I don&apos;t talk
much, even among family members. Since then, we have spoken for uncountable
hours, discussing our priorities, ambitions, goals, thoughts about life, likes,
dislikes, etc.&lt;/p&gt;
&lt;p&gt;It may be initial excitement or infatuation, but I can feel the emotions of care
and love blossoming in me. These are some unfamiliar emotions for me. I have
never attached to any human being other than my parents. Now having the same
feelings for a stranger is difficult to digest. I don&apos;t know if love can blossom
so quickly. But if it does, then I am definitely in love. And if it doesn&apos;t, it
will happen soon.&lt;/p&gt;
&lt;p&gt;When I broke the news on Instagram, many people asked me one question - Why so
early? While there were no particular reasons behind my decision, in retrospect,
I think this was an excellent decision to take at this juncture of my life.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I am currently stagnating in my life and career. I am going through that
phase where I don&apos;t see any yield of my work on both personal and
professional fronts. Although I am confident that I will reap the results of
this work in the future, the present appears to be the best time to welcome
another person into my life. I hope her entry into my life and the resultant
influence will help me come out of this slump phase. I must mention that this
is a double-edged sword, and I am taking a huge risk here. But that is
something only time will tell.&lt;/li&gt;
&lt;li&gt;My parents would have started forcing me to get married in the next year or
two. I preferred not to juggle between Bengaluru (or elsewhere) and Jaipur,
hoping to find a match. I have seen my cousins struggling with that.&lt;/li&gt;
&lt;li&gt;I had planned to go for a corporate-sponsored graduate program. But then I
left Cisco, and since Netskope doesn&apos;t have any such program; I had to put
this plan on hold for a couple of years. So, I am relatively free at this
point in my life. I believe there couldn&apos;t have been a better time to hook up
than this.&lt;/li&gt;
&lt;li&gt;After the pandemic began, I came back to my hometown. Since then, my life has
become highly monotonous, and I was looking for some respite from it. I was
feeling the need for another person in my life who could push me out of my
comfort zone while also respecting my boundaries.&lt;/li&gt;
&lt;li&gt;Perhaps I was also looking for lady luck.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/vishi_and_yash.CLoHSJhz_1rePOR.webp&quot; alt=&quot;Vishi and Yash&quot; title=&quot;Vishi and Yash&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2816&quot; height=&quot;4152&quot;&gt;&lt;/p&gt;
&lt;p&gt;Marrying means leaving your bachelorhood behind, and that has its downsides.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Time spent on your family means you can&apos;t spend time on your career and other
outside-of-work activities. But I think, at some point, I had to find a
balance anyway.&lt;/li&gt;
&lt;li&gt;The responsibility to maintain a family is not an easy one. It comes with its
challenges. Bachelorhood is relatively easy; you are on your own. But in
married life, someone else is looking up to you for constant support,
dedication, and love. I wonder how long it will take me to adjust to this.&lt;/li&gt;
&lt;li&gt;Your goals and ambitions are not only yours anymore. They get shared with
your spouse. And if the spouse is not supportive, life can take a downturn
quickly.&lt;/li&gt;
&lt;li&gt;You can&apos;t just think about yourself selfishly. You need to consider the
effect of every decision of yours on your spouse as well. It can get clumsy
sometimes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As usual, I have spoiled this post by talking about ups and downs 🤣. My habit
of weighing everything in pros and cons will not die so quickly 🤓. But I want
to clarify one thing: I am thrilled and content with my decision.&lt;/p&gt;
&lt;p&gt;I am looking forward to this alliance and spending more time getting to know
Vishi 💗. I hope I will be a worthy partner to her.&lt;/p&gt;</content:encoded></item><item><title>ISRO interview experience and takeaways</title><link>https://yashagarwal.in/notes/isro-interview-experience-and-takeaways/</link><guid isPermaLink="true">https://yashagarwal.in/notes/isro-interview-experience-and-takeaways/</guid><description>A detailed account of the author&apos;s ISRO Scientist interview, sharing insights on technical questions and career journey takeaways.</description><pubDate>Sat, 29 Jan 2022 09:01:58 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post was originally written on Jan 29, 2022 but I never posted
it. Posting it now keeping the original authoring date, but with commit date of
Aug 05, 2022.&lt;/p&gt;
&lt;p&gt;This post was on my bucket list for almost one year, but I kept ignoring it for
one or another reason. Anyway, I wanted to write this post to add my experience
to several other interview experiences to help others. Another intention was to
document this experience for my own consumption in the future to relive one of
the greatest moments in my life and career without worrying about diminishing
memory.&lt;/p&gt;
&lt;p&gt;I had decided to take the ISRO exam as part of my GATE preparation strategy. The
paper was apparently very lengthy and came with time-consuming calculations.
With some difficulty, I could solve a fair number of questions. Then, I forgot
about this and started focusing on my GATE preparation again. The GATE journey
is also memorable, which I may describe in a future post. While I was waiting
for results for both ISRO and GATE, the pandemic hit the country, and I made a
quick jump back to my hometown. The pandemic also delayed the ISRO results. But
when it was announced, it was a surprise for me. I was selected for further
interview rounds. Then, a long wait ensued. I had to wait till February 2021 to
get an interview call. I attended the interview for the post of &apos;Scientist&apos; in
ISRO on March 4, 2021, in New Delhi.&lt;/p&gt;
&lt;p&gt;I had been part of very few interviews in my life until ISRO&apos;s interview. I
could count them on fingers -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;SSL admin interview at NITC (which I rocked :P)&lt;/li&gt;
&lt;li&gt;The Directi interview (where I reached till last round), and&lt;/li&gt;
&lt;li&gt;The Cisco interview (I rocked this one too).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I haven&apos;t been part of any other interview in my life, so far. So, I am notably
less experienced in giving interviews. But, unlike other fields in my life, I
have never felt nervous while giving interviews. I am not yet sure of the exact
reasons behind this confidence. Perhaps, I am not an introvert as I think I am.&lt;/p&gt;
&lt;p&gt;Anyway, the decision to attend or not attend the interview was tough. There were
many reasons -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;What if I get selected for the interviews! The pressure to join ISRO will be
enormous.&lt;/li&gt;
&lt;li&gt;What if I get COVID during the journey or stay in New Delhi!&lt;/li&gt;
&lt;li&gt;If I am not interested in joining ISRO, why should I waste money on travel
and accommodation!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;My parents didn&apos;t know that I had taken the ISRO exam. So, it was a pleasant
surprise for them. I decided to attend the interviews because my parents looked
ecstatic about this opportunity. My brother accompanied me to Delhi; we stayed
in a nice hotel, ate good food, and visited some excellent locations in Delhi
together.&lt;/p&gt;
&lt;p&gt;Coming to the primary purpose of this post, how was my interview experience?
Well, it was a mixed bag. I wasn&apos;t satisfied with some of my answers, but I
could feel that the interview panel liked my answers. Like all other interviews
I have given, this interview revolved mostly around Linux, Networking, OS, and
Security. One good thing about ISRO interviews is that ask your preferred
subjects before starting the discussion. I said that my favorite subjects are
OS, Security, and Networking. They did ask me why I don&apos;t like DBMS. I told them
that I had never worked with DBs until now, so I am not very familiar with its
practical aspects. After that, they asked me questions from my preferred domains
only. As expected, I had absolutely no issues answering most of the questions
accurately. There were some tricky questions where they tried to stress-test me,
but I was able to deflect them.&lt;/p&gt;
&lt;p&gt;Although I had to be physically present at the ISRO center, the actual interview
happened virtually on Cisco WebEx (!).&lt;/p&gt;
&lt;p&gt;Below is an inaccurate version of the converstaion -&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interview Panel (IP):&lt;/strong&gt; Please introduce yourself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; Introduced myself. The panel specifically asked about my graduation
details and final project details.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IP:&lt;/strong&gt; So, you work in Cisco. What are you doing there?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; Explained my work in Snort and FTD team&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IP:&lt;/strong&gt; What purpose does FTD serve?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; Explained in brief, as I had just joined the FTD team at that time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IP:&lt;/strong&gt; We are using FTDs in ISRO. It is giving us too many issues. How do we
fix it?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; Suggested some solutions, including Hardware and Software ones. They
tried to stress-test me on this. Thankfully I didn&apos;t lose my patience and kept
giving them some answers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IP:&lt;/strong&gt; What happens behind the scenes when you type a web address in the
browser?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; Explained&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IP:&lt;/strong&gt; How does the router know where to forward the packet?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; I fumbled a bit on this one because I did make a mistake in the previous
question. Anyway answered it correctly in the end.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IP:&lt;/strong&gt; What is page fault and context switch? Does a page fault require a
context switch?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; Answered. Don&apos;t remember the answer now. It is very clearly explained in
OSTEP.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IP:&lt;/strong&gt; How is kernel mode switched?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; Explained&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IP:&lt;/strong&gt; What is a trap? What does the trap handler do? How is it invoked?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; Explained&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IP:&lt;/strong&gt; Explain Linux File Permissions? How to interpret directory 555 and file
777 permissions?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; Explained&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IP:&lt;/strong&gt; Do you know about the security of OS?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; Explained some concepts. I mentioned Linux Hardening, then they asked
many questions on the overall idea of hardening of the OS.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IP:&lt;/strong&gt; How to modify a Kernel to work with resource-constrained devices?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; I explained some modifications, like removing unnecessary drivers and
blobs used for generic purposes, etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IP:&lt;/strong&gt; What is a TCP wrapper? Do you know about Netstat?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; I didn&apos;t know about TCP wrappers, so I said I don&apos;t know. Explained
Netstat briefly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IP:&lt;/strong&gt; How can we improve the security of an OS?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; I explained some ways to secure OS connected to a network by installing
some tools and firewalls, like Fail2Ban, FTDs, UFW, etc. They were expecting
IPTables, so they asked about it next.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IP:&lt;/strong&gt; What are IPTables? Do you know about chains in IPTables?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; I explained IPTables, but couldn&apos;t answer the concept of chains.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IP:&lt;/strong&gt; Explain some common web attacks?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; I explained OWASP Top 10 and a few attacks like SQL Injection, XSS, etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IP:&lt;/strong&gt; Which attacks are possible in an OS?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; Explained buffer overflow, heap overflow, stack smashing, etc.&lt;/p&gt;
&lt;p&gt;In the end, they asked some general questions about Linux Kernel, which I don&apos;t
remember now. Then they concluded the interview and asked me to leave. The
interview took around 30-45 minutes. The discussion entirely revolved around the
systems side of things, which worked in my favor.&lt;/p&gt;
&lt;p&gt;I analyzed my performance after the interview. There were some things that I
would like to fix in the future.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;While preparing for GATE, I didn&apos;t focus on making notes. Having short notes
helps at the last moment. I suffered because I had to go through the entire
syllabus again, even for a quick revision.&lt;/li&gt;
&lt;li&gt;I have improved my communication skills significantly, but they are still not
up to the mark. My inherently introverted nature keeps pulling me back.
During this interview, I fumbled quite a bit. It may be that seeing myself on
camera on screen made me self-conscious. Still, I need to work on this aspect
of my soft skills because I am sure that I will need to use communication
skills a lot in the coming future.&lt;/li&gt;
&lt;li&gt;My knowledge of Linux, Networking, and OS is invaluable. I need to make sure
that I don&apos;t neglect them in the future and keep myself up to date with the
latest trends in the field.&lt;/li&gt;
&lt;li&gt;I severely lack focus and motivation. Even during the interview, I faced
issues with focusing on the questions. My mind keeps on having distracting
thoughts. I need to find some ways to improve my focus significantly.
Otherwise, my mind will lose its capabilities even faster with growing age.&lt;/li&gt;
&lt;li&gt;My understanding of Cisco products is severely limited. I spent three years
in Cisco. Still, I don&apos;t know much about any Cisco product lines completely.
I don&apos;t even know about all Cisco&apos;s Security unit&apos;s products, even after
spending my entire 3 years there. This is a difficult situation.
Unfortunately, now that I have left Cisco, there is no way/reason to get that
understanding.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The results came in September 2021, and to my surprise, I was selected for the
post with AIR 30. My final marks in the written exam were 110/216 (some
questions were canceled), and I scored 83.18/100 in interviews. However, I
decided not to join ISRO because the center assigned to me didn&apos;t align with my
interests and other reasons that I mentioned in a
&lt;a href=&quot;https://yashagarwal.in/notes/why-i-decided-to-not-join-isro/&quot;&gt;separate post&lt;/a&gt;. My parents were
delighted with my achievement; however, they supported my decision not to join
ISRO.&lt;/p&gt;
&lt;p&gt;August 2018 to February 2020 was a very frustrating yet fruitful phase of my
life. The knowledge I acquired during this time helped me overcome my self-doubt
due to my failures in academics in NITC. Getting selected for ISRO made the
entire process memorable in the end. I will always cherish this achievement of
mine.&lt;/p&gt;</content:encoded></item><item><title>Why I decided to not join ISRO?</title><link>https://yashagarwal.in/notes/why-i-decided-to-not-join-isro/</link><guid isPermaLink="true">https://yashagarwal.in/notes/why-i-decided-to-not-join-isro/</guid><description>Explore the personal and professional reasons behind my decision to decline a prestigious scientist position at ISRO.</description><pubDate>Wed, 26 Jan 2022 15:19:58 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post was originally written on Jan 26, 2022 but I never posted
it. Posting it now keeping the original authoring date, but with commit date of
Aug 05, 2022.&lt;/p&gt;
&lt;p&gt;Sometimes, life presents you with some choices that it becomes tricky to choose
any one of them. Last year, my turn came when I was selected for a prestigious
job at Indian Space Research Organization (ISRO). I was chosen for the post of
Scientist in the organization. The pay was top notch with the pay grade
equivalent to that of new bureaucrats. The pride that comes with the service to
the nation was also associated with the job. I could have enjoyed my life
without any worry about layoffs, pay cuts, workload, always having to learn new
things, etc. But I decided to leave the offer and continue with what I was
doing.&lt;/p&gt;
&lt;p&gt;Why did I do that? Was I mad? It has been almost one year since my final
interview and nearly 3 months since I declined the offer. In this post, I intend
to publicize my reasons for not joining ISRO. You may or may not agree with a
lot of these reasons (even I doubt some of my decisions), but don&apos;t hesitate to
voice your opinion. Perhaps, it will give me another perspective to think about
similar situations in the future.&lt;/p&gt;
&lt;h1 id=&quot;the-job-profile-and-assigned-isro-center&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-job-profile-and-assigned-isro-center&quot;&gt;The job profile and assigned ISRO center&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I studied Computer Science during my undergraduate and have been working in the
software industry since then. I know I can learn any new field (aerospace
engineering, in this case) if I want to. Still, it was not a financially
lucrative choice, and also it was not in alignment with my interests.&lt;/p&gt;
&lt;p&gt;I was assigned to NRSC, Hyderabad, which would be my base for the rest of my
career. NRSC stands for National Remote Sensing Center. As I understand it, the
NRSC primarily works on analyzing the images and media received from various
ISRO satellites. I have never been an enthusiast of the field of computer vision
and image processing (perhaps because of the maths associated with it). So I
wasn&apos;t very keen on doing something which does not align with my current
interests. Although, one can say that you start loving anything if given enough
time. But I wasn&apos;t very sure about taking chances.&lt;/p&gt;
&lt;p&gt;Of course, I queried about the possibilities of transfer to some other center. I
was told that the chances of a transfer are slim unless there are exceptional
circumstances or a mutual transfer.&lt;/p&gt;
&lt;h1 id=&quot;the-location&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-location&quot;&gt;The location&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;As I mentioned earlier, if I had accepted the offer, I would have been bound to
Hyderabad for the rest of my career. This was totally unacceptable to me. Many
things have changed globally since the pandemic started, and the work location
flexibility is one of the positive changes. Earlier, it was challenging to work
from home, but now, it is/will be accepted as an industry norm. ISRO, being a
government organization and from a national security perspective, will not allow
its employees to work from home, rightly so. At present, I would perhaps be okay
with the idea of exploring the world and staying away from the family. Still, I
would like to settle down at some familiar place in the longer run. Joining ISRO
would have stolen that possibility from me ultimately, if not immediately.&lt;/p&gt;
&lt;p&gt;I have been staying at my home for the last 2 years due to COVID lockdowns. This
has affected my psyche at a deep level. I no longer wish to stay away from my
parents. The detachment caused by my 7 year-long explorations ended with COVID
lockdown. It will be tough for me to stay away from them for any long duration
now. Air travel has reduced the distances drastically, but the possibility of a
WFH-friendly future has spoiled me. ISRO is unlikely to provide this kind of
option in the foreseeable future.&lt;/p&gt;
&lt;h1 id=&quot;money&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#money&quot;&gt;Money&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Money always plays a part in every decision a working adult takes. While the
starting salary given by ISRO is comparable to private sector companies, the
yearly increments are peanuts. One gets 18% conditional increment + possible
promotions every four years, which looks terrible compared to MNCs. Although
joining ISRO comes with certain other perks which will definitely match or even
outshine the overall CTC offered by MNCs in some cases.&lt;/p&gt;
&lt;p&gt;Suppose I had decided to join ISRO in an alternate universe. In that case, I
could have given you a lot of reasons why money should not be a factor in
deciding whether to take the job or not. So, I will stop discussing the
importance of money in a job offer here.&lt;/p&gt;
&lt;h1 id=&quot;not-my-kind-of-government-job&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#not-my-kind-of-government-job&quot;&gt;Not my kind of government job&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Government jobs are lucrative in India. They pay decent, have excellent perks,
give life-long job security, and calm and peaceful life on most days. However,
you can divide the government jobs into three categories -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Those with power, status, money, meaningful work, and hectic life&lt;/li&gt;
&lt;li&gt;Those with meaningful work, money, and peaceful life but no power and status&lt;/li&gt;
&lt;li&gt;Those with peaceful life (?), nothing else&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In my opinion, ISRO&apos;s job falls into category 2, where you have good work,
money, and life but no power or status. I have good work and money in the
private sector (life is a hit or miss). So, I couldn&apos;t find any reason good
enough to join ISRO. If I had the option to choose a job from category 1 (for
example, all India services), I wouldn&apos;t have given a second thought to the
idea. My current thinking is that if I have to live someplace other than my
hometown, I would like to have either big money or power and social status.&lt;/p&gt;
&lt;h1 id=&quot;it-wasnt-my-original-target&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#it-wasnt-my-original-target&quot;&gt;It wasn&apos;t my original target&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I attempted the ISRO exam to get some additional practice for the GATE exam. I
had plans to get into some good colleges (IISc!) for further studies. ISRO&apos;s
exam format coincides very much with the GATE&apos;s. So I thought that it would be
an excellent opportunity to get some much-needed real exam experience. There was
no other aspect to this fact. If I had taken the exam intending to join ISRO on
selection, it would have been effortless to convince myself. But, in my
scenario, I could not convince myself about the opportunity. Some may say that
not everybody gets this opportunity, and I should have accepted it happily. I am
sorry, but I don&apos;t subscribe to this viewpoint. I understand that the gods were
kind enough to provide me with this opportunity. But I firmly believe that the
same gods would also appreciate my reasoning about the decision to decline the
offer.&lt;/p&gt;
&lt;p&gt;For some people, these reasons may seem non-important. My personal circumstances
and professional ambitions, and my self-confidence (perhaps over-confidence)
contributed to my final decision to decline the ISRO offer. It is very much
possible that I may regret this decision in the future when my life takes a
downturn. I hope that this post will remind me of my present situation and bring
me out of my grief. The decision taken is what matters now. I should focus on
the next minute, hour, day, month, and years to come.&lt;/p&gt;
&lt;p&gt;Wish me luck 🍀&lt;/p&gt;</content:encoded></item><item><title>Things I learned in Cisco</title><link>https://yashagarwal.in/notes/things-i-learned-in-cisco/</link><guid isPermaLink="true">https://yashagarwal.in/notes/things-i-learned-in-cisco/</guid><description>A candid look at three years at Cisco: professional growth, working with diverse tech, and personal reflections on culture and missed opportunities.</description><pubDate>Sat, 22 Jan 2022 16:15:24 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post was originally written on Jan 22, 2022 but I never posted
it. Posting it now keeping the original authoring date, but with commit date of
Aug 05, 2022.&lt;/p&gt;
&lt;p&gt;After three years at Cisco, I finally decided to explore other opportunities
in 2021. 22/01/2022 was my last day in Cisco. It has been an exhilarating
journey. Even more so because it was my first such journey. I thoroughly enjoyed
my time at Cisco, both professionally and personally.&lt;/p&gt;
&lt;p&gt;Cisco provided me ample chances to work on a variety of problems. I started in a
totally independent role exploring various open-source products and developing
POCs integrating multiple open-source tools to the Cisco product line. I worked
with OPA, ModSecurity, OpenRASP, etc. along with evaluation of Signal Sciences,
K2 etc. We also worked on identifying differences between Snort&apos;s http module
and ModSecurity, apart from developing POCs to identify supply chain attacks by
evaluating the build artefacts generated in a CI pipeline.&lt;/p&gt;
&lt;p&gt;Later I got a chance to work with a typical product development team when I
switched to Snort team where I worked on the FTD integration for Snort, and
helped in shipping high-quality code enhancing legacy Cisco firewalls. I also
got an opportunity to contribute to some significant components to the very
early stage Secure Firewall Cloud Native (SFCN) – Cisco&apos;s own cloud-based
security solution – where I introduced an important component required for
health monitoring in the SFCN clusters. Throughout my tenure at Cisco, I got
opportunities to work on both the legacy (Lina ASA - a 20-year-old product) and
the latest tools and technologies – Kubernetes, Docker, Terraform, Prometheus
etc.&lt;/p&gt;
&lt;p&gt;But, work was not the best thing about Cisco. The work was, of course,
excellent, but what makes Cisco a dream company for many is its people. The
culture that Cisco imbibes is pure gold. I don&apos;t know how the rest of the
industry operates in this department, simply because of my inexperience. But for
a novice like me, Cisco provided an ideal launchpad. I have many regrets about
my time at Cisco, more on this later in the post. The people I met and worked
with throughout my time in Cisco were exceptional in their work and, at the same
time, were quite humble and down to earth in their dealings with me. I have also
heard about some bad experiences from people working in Cisco, so I may have
been fortunate in this aspect. Exceptions are everywhere, but they should not be
the norm. And the toxicity is definitely not the norm in Cisco.&lt;/p&gt;
&lt;p&gt;While I learned a lot of things in Cisco, there were a lot of opportunities that
I didn&apos;t utilize while in Cisco. There used to be many hackathons, patentothons,
cultural, literary, technical clubs, and sporting facilities in Cisco. Many of
my friends were part of these activities, and some even led the organizing teams
of these event. I never tried to contribute to any of these events. I had some
personal and professional reasons behind this lack of enthusiasm. One of my
colleagues criticized me &lt;strong&gt;privately&lt;/strong&gt; for this on my last day - &quot;Yash, I wish
you had shown more involvement during the team building activities.&quot; I have been
an introvert throughout my life, and changing one&apos;s personality is not easy. But
this is something I will actively try to avoid repeating.&lt;/p&gt;
&lt;p&gt;Now, you may ask, if everything was so rosy about Cisco, why did you leave,
Yash?&lt;/p&gt;
&lt;p&gt;Well, the reasons are many folded -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I am only 25. It is not a time to settle for me.&lt;/li&gt;
&lt;li&gt;I was trying to break away from the traditional network security domain. I
have been interested in distributed systems and cloud security. Still, my
current team was not an ideal place for this. Switching to some other team
inside Cisco was an option. But I decided to explore the industry from
another perspective by changing the company.&lt;/li&gt;
&lt;li&gt;Few more reasons that are not as important to mention here.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Anyway, Cisco will always have a special place in my heart for introducing me to
the corporate world.&lt;/p&gt;
&lt;p&gt;It is farewell for now. Au Revoir, Cisco!&lt;/p&gt;</content:encoded></item><item><title>2021 - A Bullish Year</title><link>https://yashagarwal.in/notes/2021-a-bullish-year/</link><guid isPermaLink="true">https://yashagarwal.in/notes/2021-a-bullish-year/</guid><description>A 2021 year in review, detailing personal transformations, health achievements, significant career moves, and reflections on blogging challenges.</description><pubDate>Tue, 04 Jan 2022 16:55:24 GMT</pubDate><content:encoded>&lt;p&gt;2021 was a year of realigning priorities for me. I started the year with a set
of goals, expectations, and an enthusiasm to achieve these, and here I am,
ending the year with entirely different objectives and perspectives. There were
a few ups and downs throughout the year, but collectively, these have
transformed me into a more fitter, confident, enthusiastic, and curious version
of my past self.&lt;/p&gt;
&lt;h1 id=&quot;health&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#health&quot;&gt;Health&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;If you read this blog regularly, you may know that I have been struggling to
make health a priority in my life for the last few years. This year also started
on the same note. I started with 65 kgs of weight, and by the end of July, my
weight had increased to 71 kgs. I have been underweight for most of my life, but
I probably became obese for the first time on the BMI scale this year. And I am
not very proud of this, even though I always desired to gain some weight while
growing up. I have long realized the importance of exercise in daily life but
never acted on it seriously.&lt;/p&gt;
&lt;p&gt;Nonetheless, this year I finally managed to work on it. Since September, I have
reduced my weight from 71 kgs to 62 kgs. More importantly, I could bring my BMI
down to an optimum level.&lt;/p&gt;
&lt;p&gt;Another important aspect of health that I am working on is sleep. For some years
now, I have been working on regulating my sleep timings and the time I spend
sleeping at night. I have data about my sleep duration for the entire year.
Using that, I produced the chart below, which shows that I have managed to sleep
at least 8 hours on average (this also includes afternoon naps).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/average_sleep_duration.njt1un9j_Z2uHbsR.webp&quot; alt=&quot;Sleeping in 2021&quot; title=&quot;Sleeping in 2021&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1236&quot; height=&quot;500&quot;&gt;&lt;/p&gt;
&lt;p&gt;One of my last year&apos;s goals was -&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Sleep at proper times - … I will try to sleep by 10 PM and sleep for at least 8 hours every day. I am aiming for an 80% success rate in this aspect.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I feel that I have managed to achieve this goal with a good level of accuracy.&lt;/p&gt;
&lt;h1 id=&quot;career&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#career&quot;&gt;Career&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This year, I completed three years in Cisco. It has been a wonderful experience.
However, I had a feeling that I should move on and start exploring the industry
from a different perspective. So, I decided to go back to the interview table.
In 2022, I will be joining a late-stage US-based cloud-security startup. I will
write a separate post describing my experience preparing and attending the
interviews.&lt;/p&gt;
&lt;p&gt;I had to make a rather tough decision about my career this year. When I was
preparing for GATE, I also decided to take the ISRO exam. The idea was to get
some additional practice from the GATE perspective. After clearing the written
test and the interviews, I got an all-India rank of 30 in the exam. As a result,
I was offered a Group-A post of Scientist in NRSC Hyderabad. However, it didn&apos;t
align with my vision and plans for the future, so I decided to decline the
offer. I hope to write a long-overdue post about my experience with this
sometime in 2022.&lt;/p&gt;
&lt;h1 id=&quot;blogging-and-writing&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#blogging-and-writing&quot;&gt;Blogging and Writing&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The fact that I could not post this review on the first day of the year is a
testament that I am struggling with writing. I am not in the proper mindset to
write anything. I have tried to start small, but writing even a single sentence
seems like a burden. Throughout 2021, I had a nagging feeling that I should
write, but I couldn&apos;t find the enthusiasm to sit down and get going.
Unfortunately, I don&apos;t even see myself writing anytime in the foreseeable
future.&lt;/p&gt;
&lt;p&gt;I notice that the procedure used to publish anything on this blog is very
complex. Unlike WordPress, I have to battle with markdown, git, code editor,
etc., to publish a post and make subsequent updates. The complexity associated
with the static sites seems to have created a block in my mind. Unfortunately,
developing a new website is no longer a priority for me. And I am not yet ready
to accept the tradeoff between spending money on WordPress hosting and the
comfort of writing in Wordpress&apos;s editor.&lt;/p&gt;
&lt;p&gt;I planned to journal regularly in 2021. I started with that, but soon it turned
into a logbook kind of activity. Instead of introspecting over my day, I started
tracking each hour of the day, which was not the intention. So around July, I
stopped doing it.&lt;/p&gt;
&lt;h1 id=&quot;reading&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#reading&quot;&gt;Reading&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I had set a target to read five books this year. I completed that goal. I read a
lot of PDFs this year, which can&apos;t be classified as books, so my reading
statistics are very much skewed for the year. However, I didn&apos;t plan properly
this year, so my efforts seem scattered and unfocused.&lt;/p&gt;
&lt;p&gt;To be very honest, I was distracted throughout the year by the continuous
flooding of information. My tendency to do everything with perfection further
made things complicated. Another troubling issue was my resistance to making
notes or summarising the books I read. I consider this an important activity
because I find it challenging to recall otherwise.&lt;/p&gt;
&lt;p&gt;I dabbled with Zettlekasten for some time this year. It is an exciting idea, but
the time required to set it up is a big hurdle. It takes considerable effort to
summarise a piece of knowledge, link it with other information, and then revise
all of it. I may not be ready for it yet, but I will be trying it again in 2022
because I am very confident about the potential of this system.&lt;/p&gt;
&lt;p&gt;I have reduced (or stopped) my Twitter usage to minimize information overload. I
felt that passively reading others&apos; views distorts my thinking and ability to
generate original ideas. Although I am not really producing any exciting ideas,
I want to keep my mind clean and free from distraction as much as possible.&lt;/p&gt;
&lt;h1 id=&quot;media-consumption&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#media-consumption&quot;&gt;Media Consumption&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I logged my sleep data, work schedules, perceived productivity levels, perceived
sleep efficiency, mobile usage patterns, etc., in a Google Sheet document.
However, around mid-year, I started to get impatient with the whole manual setup
and stopped logging my data. So, unfortunately, I don&apos;t have any way to analyze
all these patterns now. I am totally disappointed with the lack of any standard
tool that can collect at least mobile usage data while also ensuring privacy.
Rescue time is something I have thought about, but I cannot convince myself to
use that app due to privacy issues.&lt;/p&gt;
&lt;p&gt;Below are my media consumption habits from 2021 -&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/media_consumption.Dsb2Jibi_FyXrA.webp&quot; alt=&quot;Media consumption in 2021&quot; title=&quot;Media consumption in 2021&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1236&quot; height=&quot;500&quot;&gt;&lt;/p&gt;
&lt;p&gt;For some reason, I watched a lot of content in the last two months of 2021.
Possible reasons may be my acceptance of the new job offer or my truce with the
weather. For whatever reason, I consider this year a controlled one in the
binge-watching department.&lt;/p&gt;
&lt;h1 id=&quot;what-in-2022&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#what-in-2022&quot;&gt;What in 2022?&lt;/a&gt;&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Build muscles - Now that my weight is at an appropriate level, it is time for
me to build some muscles.&lt;/li&gt;
&lt;li&gt;Read 24 books - I plan to read 24 books this year. I am yet to decide if I
want to focus on a particular subject or diversify my reading.&lt;/li&gt;
&lt;li&gt;Phone usage - Planning to keep it under 3 hours. However, I need to figure out
how to export this data out of my phone.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you might have noticed, most of my failures in 2021 have something to do with
my habit of doing things perfectly. While it is good to perform any task as
cleanly as possible, it sometimes becomes a big hurdle in starting up. In 2022,
I hope to keep this tendency at bay as much as possible.&lt;/p&gt;</content:encoded></item><item><title>25, it is!!!</title><link>https://yashagarwal.in/notes/25-it-is/</link><guid isPermaLink="true">https://yashagarwal.in/notes/25-it-is/</guid><description>A candid reflection on turning 25, exploring personal struggles with imposter syndrome, social comparison, and the journey of self-discovery.</description><pubDate>Sun, 06 Jun 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I turned 25 in the week gone by. I have been on the earth for a quarter of a
century now, and the feelings are mixed. I love to write about myself, even at
the risk of overexposing myself to the general world. This helps me in
remembering my younger self. That, I think, is the best yardstick to judge
myself against. Unfortunately, while I should write positive things, the tone of
most of my personal experience articles tends to be negative. It is instinctive
and something that I have not learned to control just yet. Nevertheless, I will
consider myself successful when I look back at my life, and the memories make me
smile. Some of my previous posts do make me smile.&lt;/p&gt;
&lt;p&gt;The last one month or so has been tough on me. Suddenly, all my plans started to
collapse, I started feeling depressed, and the feeling of being an imposter hit
me hard once again. All this coincided with the second wave of COVID-19 in
India, and it is easy for me to blame COVID. But there are certainly other
reasons that have been building up for the last few years. The eruption of these
accumulated worries from time to time drains me down. This has been the essence
of my life for the previous few years since I started having an idea of
self-ownership.&lt;/p&gt;
&lt;h1 id=&quot;borrowing-from-future-and-past&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#borrowing-from-future-and-past&quot;&gt;Borrowing from future and past&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I see many of my friends and colleagues opting for higher studies abroad or in
top institutes of India. While I also had such plans in the past, circumstances
forced me to kneel down. I had hoped that I have adjusted to this reality. But a
constant wave of social media posts from friends and people leaving the
workplace has negatively affected my subconscious mind. Given that I decided
with maturity and complete understanding of the situation, I don&apos;t know who or
what to blame for my current mental state. I guess I just need to give it some
time, and it will subside on its own.&lt;/p&gt;
&lt;p&gt;I often tend to compare myself against others and feel low seeing people doing
better than me. It is definitely not jealousy, but being competitive has so
intrinsically become part of me that I can&apos;t help. Somewhere deep down, I also
know that this comparison is futile. Different people can have different life
situations, and life is not the same for any two persons. A better option for me
is to compare against my younger self and see how much I have changed. That
should be easy to do, given my habit of writing my experiences frequently. I
don&apos;t know what is holding me back.&lt;/p&gt;
&lt;p&gt;When I look back at my childhood, I see a weak, frail boy bullied by good and
bad alike. Unfortunately, I never mustered the courage to fight them back. The
bullying and my subsequent retreat into a cocoon have had a lasting impact on my
life. I am still trying to reverse it. On the other hand, I still think that I
am a born introvert. My life experiences might undoubtedly have given my
personality its current shape, but it didn&apos;t all start with a blank slate.&lt;/p&gt;
&lt;h1 id=&quot;the-struggles-of-the-present&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-struggles-of-the-present&quot;&gt;The struggles of the present&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;One thing I am very proud of myself is that I never lost my curiosity. I am
still inquisitive. I love to learn anything and everything that I can put my
hands on (perhaps except artistic stuff). But what kills my enthusiasm is the
fact that I don&apos;t utilize my learnings in any way. I tend to live my life in the
same way I have been living it till now. There is no adventure whatsoever in my
life, as I see it. It is as if whatever new I learn doesn&apos;t make any impact on
my day-to-day life. When I think about it deeply, it appears to be a very
unfortunate aspect of my quest for knowledge.&lt;/p&gt;
&lt;p&gt;For instance, let us talk about reading. I agree that we should not read to
remember, and that way, definitely reading has given me some new perspectives. I
have read anywhere between 90-100 good quality books in the last one and half
years. During a typical day, I get many insights related to whatever I have
read. But when I sit down to articulate them in the form of a blog post or a
personal note, I go blank. According to my introspection, it seems that most of
my learnings are just superficial and I suffer from so-called illusion of
knowledge. This reminds me of a quote by Daniel J. Boorstin -&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The greatest enemy of knowledge is not ignorance, it is the illusion of knowledge.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Another thing is my short attention span. I can&apos;t focus on one thing for more
than a couple of minutes now. This is one thing that has deteriorated over the
years as I become more and more connected. I know that meditation will
definitely help me with this issue. Still, I can&apos;t find the motivation to keep
meditating continuously. I can start meditating any day. I can continue it for
some days by using my willpower, but this is not sustainable. With a limited
stock of willpower, I am bound to fail unless I make meditation a habit. I have
almost cut myself from social media, instant messaging apps, and all other forms
of communication to focus on the important stuff in my free time. Still, somehow
my attention betrays me every single time.&lt;/p&gt;
&lt;p&gt;For a couple of years now, I have been blaming my undecidedness to write
regularly on so-called &quot;writer&apos;s block.&quot; This is a complete sham. It has just
served as a cover for my laziness and unwillingness. I often convince myself
saying that I should first acquire knowledge. Then, one fine morning, I will
wake up and write world-shaking articles. Of course, this is never going to
happen, but why not, it is a good excuse to keep me happy with my comfort zone.&lt;/p&gt;
&lt;h1 id=&quot;conundrums-of-asking-for-help&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#conundrums-of-asking-for-help&quot;&gt;Conundrums of asking for help&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;There have been many people in my life who have offered to guide me and help me
realize my goals. However, my reserved nature and the feeling of being an
imposter have stopped me from opening up to anyone. I have been struggling with
imposter syndrome for the last 3-4 years. I am not sure about the reasons yet.
Still, I think my hesitation in requesting a &quot;familiar&quot; person for mentorship
arises from the feeling that I might not perform as they would expect me to do.
That would shatter my image in front of them. Therefore, my subconscious mind
has decided that it is more optimal to keep the (false?) impression intact
instead of getting the required help. That might also answer why I never share
my articles with anyone. It is a fact that I don&apos;t feel very confident about
myself and my work. It has affected me at the workplace, and perhaps it will
continue affecting me in the coming years. The only way I can think of to get
rid of this problem is to face it.&lt;/p&gt;
&lt;p&gt;I have also often struggled to take criticism constructively. Somehow my
egoistic nature and perfectionistic tendencies mixed with imposter syndrome make
it challenging to learn from criticism. Just to clarify, I don&apos;t mean that I
harbor any ill thoughts for the criticizer. It is something personal, and I
don&apos;t have any words to describe it right now.&lt;/p&gt;
&lt;h1 id=&quot;the-illusion-of-competence&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-illusion-of-competence&quot;&gt;The illusion of competence&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;While reading has given me new and unique perspectives to think about the world,
it has also given me an illusion of competence. I feel like I know a lot, but
when it comes to utilizing the &quot;earned&quot; knowledge, I cannot interconnect my
thoughts. I have seemingly different areas of interest, and that is reflected in
my reading habits. My expectation is that diverse reading habits will result in
a future me who will gather ideas from multiple fields and interconnect them to
build a novel abstraction. I am not sure if this is a far-fetched desire and
even possible for an average human. But I can&apos;t push myself away from this
thought. Over the years, this has become one of many ambitions to get to that
state. I don&apos;t know if I will ever reach that point, but I don&apos;t see any harm in
keep trying. My only worry is how to stay away from the illusion of expert-level
competence in a field, while I don&apos;t know actually have any expertise.&lt;/p&gt;
&lt;h1 id=&quot;the-political-me&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-political-me&quot;&gt;The political me&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Those who know me in my personal life will attest that I am not able to stay
loyal to any one side of the political spectrum. I have always see-sawed between
left and right. Of course, this see-sawing has subjected me to &quot;gentle&quot; bashing
from my friends adhering to either ideology. Famous Hindi poet Ramdhari Singh
Dinkar very accurately points out the situation -&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;समर शेष है, नहीं पाप का भागी केवल व्याघ्र, &lt;br&gt;
जो तटस्थ हैं, समय लिखेगा उनका भी अपराध।&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But then, he says -&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;जो सत्य जान कर भी न सत्य कहता है,&lt;br&gt;
या किसी लोभ के विवश मूक रहता है,&lt;br&gt;
उस कुटिल राजतन्त्री कदर्य को धिक् है,&lt;br&gt;
यह मूक सत्यहन्ता कम नहीं वधिक है।&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now, this is one of the paradoxes that troubles me quite frequently. While
taking sides mean losing some of your individuality, not taking sides is also
equivalent to not having a clear goal in mind, in a way.&lt;/p&gt;
&lt;p&gt;Since when I started reading profusely, I have tried to keep this balance
intact. I have made conscious efforts not to form &lt;em&gt;strong&lt;/em&gt; opinions and not
adhere to one particular ideology without looking at facts and data. The
engineer&apos;s mind weighs everything in terms of data and facts and filters out
personal opinions.&lt;/p&gt;
&lt;p&gt;I read a lot about foreign policy, society, culture, caste, religion, economy,
history, and the constantly evolving political structure of India and the World.
But, unfortunately, most of the quality media is dominated by the left. I don&apos;t
want to engage with keyboard-warriors on Twitter, WhatsApp, and elsewhere, so
that leaves me with significantly less material to know the genuine viewpoint of
the other side.&lt;/p&gt;
&lt;p&gt;Over the years, I have realized that socially I tend to be on the center-left
and economically, on center-right. But sharing political views in the public
domain without proper research is not ideal. I want to consolidate my learnings
and form well-informed and well-analyzed opinions on happenings in the world in
general and India in particular before I participate in political discourse. It
does not mean that I don&apos;t have any political opinions. Most events cannot be
categorized as good or bad; it is just how one wants to perceive the world.
Therefore, I constantly try to avoid getting influenced by what a random
journalist with certain motives, sitting in a high-rise AC office, might want me
to believe.&lt;/p&gt;
&lt;h1 id=&quot;the-cs-guy&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-cs-guy&quot;&gt;The CS guy!&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Though I hated Computer Science a couple of years back, I have worked on my
fears. Now, at least I don&apos;t have any understanding issues with the core CS
subjects (except DBMS, perhaps. I don&apos;t like it; at all!) I didn&apos;t focus on
understanding whatever CS theory was taught during my undergraduate (again, a
lack of proper mentorship.) Although this doesn&apos;t harm me in my professional
life, I want to get some kind of research experience at some point in my life.
Unfortunately, it seems unlikely for me to enroll in a full-time graduate
program in the foreseeable future. So, I am weighing my options to go for a
Systems course via online studies. Assuming I get admission, one option is a
sponsored graduate program (such as this
&lt;a href=&quot;https://iken.iisc.ac.in/mtech-online/&quot;&gt;one&lt;/a&gt; offered by IISc.) Another option is
to go for an online &lt;a href=&quot;https://omscs.gatech.edu/&quot;&gt;MS degree&lt;/a&gt; provided by some US
universities. I will surely miss the unique campus experience, but I hope it
will still quench my intellectual thirst. I currently have some other stuff on
my plate. I will try to finish them before deciding if and when I should opt for
these options. I hope to make a call in the next two years in the worst-case
scenario.&lt;/p&gt;
&lt;h1 id=&quot;originality&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#originality&quot;&gt;Originality&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;By originality, I mean a way to build upon something existing – some kind of
improvement upon an already existing thing, idea, or abstraction. Almost
everything humans have created has been an improvement over something preceding
it, either man-made or natural. In my opinion, originality is a creative process
to generate novel ideas improving upon existing processes, things, tools, and
knowledge systems to make them more desirable, optimized, user-friendly, and
insightful. Original need not be &quot;original&quot; in its literal sense.&lt;/p&gt;
&lt;p&gt;While I have been working on my CS skills, it is not the field where I get my
most original thoughts and ideas, despite being the subject where I spent 4
years of my life. I have met many amazing people in Cisco over the last 3 years.
I am often awestruck by their ability and passion for continuously generating
new ideas. Whether it is a Hackathon or a Patentothon, I have been fortunate to
team up with people who can generate exciting ideas with surprising depth.
However, I have thought about it and realized that I am not yet at that level
where I can generate original ideas worthy of patenting or publication. Some
people are just born with that kind of talent, and some acquire skills superior
to any talent. With growing experience, I might get to that level someday, but
currently, I am yet another average Indian software engineer. Read the last
section of this article to know why I am content with this situation for now.&lt;/p&gt;
&lt;p&gt;On the other hand, the fields where I tend to get many ideas nowadays are
religion, politics, and history. One possible reason behind this might be that
these subjects are my area of interest nowadays, and I read related books during
my non-work day. So my mind gets a lot of time to consolidate this stuff.&lt;/p&gt;
&lt;p&gt;It is such a contentious issue for me that I feel embarrassed talking about it.
In fact, this is the first time I have actually given any thoughts on this
topic. And I am glad that I did it. I wrote above my initial impressions about
an issue I was unaware of until a few moments ago. I hope to get more clarity
and insights into the real reasons behind my lack of enthusiasm to produce new
ideas in the coming time.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Even if not entirely by choice, I am trying to embrace the slow-growth mindset,
taking short-term hits for long-term gains. I hope this gamble will pay off, as
I think it will be the right approach. Long-term gains far outweigh short-term
benefits when it is a matter of whole life.&lt;/p&gt;
&lt;p&gt;While I keep whining about my future and past and try to piece together my
present, this quote sums up the way forward succinctly –&lt;/p&gt;</content:encoded></item><item><title>Thoughts on the Family Man 2</title><link>https://yashagarwal.in/notes/thoughts-on-the-family-man-2/</link><guid isPermaLink="true">https://yashagarwal.in/notes/thoughts-on-the-family-man-2/</guid><description>Reflecting on &apos;The Family Man 2&apos;, I explore complex themes of ethnic conflict, morality, and human rights, posing deep questions.</description><pubDate>Sat, 05 Jun 2021 11:45:02 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/the-family-man-2-cover.C060Qa_g_21aMFV.webp&quot; alt=&quot;The Family Man 2&quot; title=&quot;The Family Man 2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1200&quot; height=&quot;630&quot;&gt;&lt;/p&gt;
&lt;p&gt;I binge-watched the second season of The Family Man (TFM) 2 last night. I was
eagerly waiting for this season of TFM for a long time, especially after the
highly gripping season 1. And I am not disappointed. While I watch digital
content very selectively (young-adult fantasy depicting a dark and mid-age
Europe and Russia and spy-genre Indian shows for occasional patriotic doses),
very few shows have such excellent cinematography. It is the plot of TFM2 that
made me ask some questions myself. While I don&apos;t have clear answers to them yet,
I thought I will just list them down, along with some of my raw thoughts.&lt;/p&gt;
&lt;p&gt;The plot is about the resistance of Eelam Tamils of Sri Lanka against the Sri
Lankan government. The topic is riddled with complex matters of morality,
humanity, human rights, ethnicity, language, majority-minority conflicts, and
the right to self-governance. Sri Lankan conflict is familiar to most Indians
because of India&apos;s involvement in the struggle in the early 1980s and 90s and
the subsequent assassination of Rajiv Gandhi during an election campaign in
Chennai. Many such issues are spread throughout the world – e.g.,
Israel-Palestine conflict, Rohingya issue in Myanmar, Nagaland in India.
Specific questions that perplex me about these conflicts are -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Why do people fight for their ethnicity? How difficult is it to live
alongside other people under a defined constitution prepared with a mutual
agreement?&lt;/li&gt;
&lt;li&gt;Why are modern nation-states reluctant to give autonomy or independence to
such groups just to avoid bloodshed?&lt;/li&gt;
&lt;li&gt;What are the causes of the origins of such conflicts?&lt;/li&gt;
&lt;li&gt;Are there any examples where the final settlement was acceptable to both
sides, and nobody left the table feeling betrayed?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I look for academic (Sociology, Anthropology, and Political Science, to be
precise) answers to these questions. I understand that ground realities are
often very different than what we learn from news media and books. Humans tend
to have a natural connection to their perceived kinsmen. Why do you think nature
has decided to keep a human baby dependent on her parents for almost 1/4th of
her average lifetime? The bond we generate with our society, tribe, kin, and
family stays with us forever, and we strive to keep them safe and secure at any
cost.&lt;/p&gt;
&lt;p&gt;I will give a controversial example - the Indian freedom struggle is a revered
movement for most Indians, including myself. Still, for the then British rulers,
it was a rebellion that had to be suppressed at any cost to save their empire.
We despise the atrocities performed by the British on Indian people. How is that
different from the horrors seen in the conflicts of the modern world (not just
the people in power, rebels everywhere have also committed unspeakable
atrocities). As I understand it, it is not a binary problem; there is no black
and white in this. There are shades of grey and what amount of black you see
depends on a lot of factors. Just be aware of the fact that the more powerful
side need not be the necessary evil. Resolving any conflict requires some
compromises from both sides. Until both sides are leaving the table feeling that
they won, no negotiation will be successful. Remember -&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We cannot negotiate with people who say what&apos;s mine is mine and what&apos;s yours is negotiable.&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title>Looking back at 2020</title><link>https://yashagarwal.in/notes/looking-back-at-2020/</link><guid isPermaLink="true">https://yashagarwal.in/notes/looking-back-at-2020/</guid><description>A personal reflection on 2020, covering health, family, and key lessons learned from a year of introspection and unexpected changes.</description><pubDate>Sun, 03 Jan 2021 10:19:58 GMT</pubDate><content:encoded>&lt;p&gt;While I thought of writing this review on 31st December, I couldn&apos;t overcome my
laziness. It has been a persistent problem with me in 2020, which I haven&apos;t been
able to fix as of now. On average, the year 2020 was a good year for me. It
wasn&apos;t equally forgiving to me on every issue of my life, but it was most
undoubtedly lenient on the issues I consider most important at this phase of my
life. As for most people, it was a year of self-retrospection for me as well. I
identified some new goals in my life, forgot some others, compromised with some
failures, and learned the value of loved ones.&lt;/p&gt;
&lt;p&gt;Like previous years, I have identified some critical areas of my life, where I
am putting more focus year after year. It is easier to focus on one topic at a
time. I have decided to omit some parts of my life from this write-up because I
am not yet ready to reveal them to a specific set of people (although very few
people read this blog now, thanks to my irregularity, I prefer to stay
risk-averse).&lt;/p&gt;
&lt;h1 id=&quot;health&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#health&quot;&gt;Health&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;2020 belonged to the pandemic. So it is most prudent to start with the topic of
health. For the last some years, I have been struggling with a lot of
health-related issues. Although this year was a much better one for my body and
mind, I am still petrified of my health issues. It seems that I am a
worry-magnet, and the worry of catching coronavirus was the biggest of them all
this year. I spent almost 3-4 months in this worry. It took some toll on my
health, but in the end, I was able to come out of it, thanks to family.&lt;/p&gt;
&lt;p&gt;I should give part of the blame to my laziness. I had stopped all my learning
activities in the mid-to-late year (perhaps I was exhausted). And that gave way
to evil thoughts in my mind. As they say, &quot;An idle mind is the devil&apos;s
workshop!&quot;. Thankfully I got hold of the situation while it was still
manageable.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/sleep_hours.DDMJFAXp_Z2ft5YY.webp&quot; alt=&quot;Sleeping in 2020&quot; title=&quot;How much I slept in 2020?&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2232&quot; height=&quot;1474&quot;&gt;&lt;/p&gt;
&lt;p&gt;This graph shows how my sleeping times changed throughout the year. I lost track
in the third quarter of the year. Anyway, in December, I seem to have come back
to the correct path.&lt;/p&gt;
&lt;p&gt;This chart doesn&apos;t convey certain things very clearly. First, it shows the
average amount of time I slept in a particular month. However, that time
includes the afternoon nap also. And in the mid-year months, where you see 9+
hours of sleep, it means that I was sleeping quite a lot in the afternoon and
less at night. In the last three months of the year, I have been trying to
regulate my sleep timings at night, and I am quite satisfied with my progress. I
have observed over the years with my sleep experiments that whenever I start
sleeping less at night, I tend to exhaust myself in the next couple of months.
This theory got validated this year when I exhausted myself from June onwards,
and my health issues reappeared after sleeping significantly less in April and
May (night sleep).&lt;/p&gt;
&lt;p&gt;I &lt;em&gt;actually&lt;/em&gt; did some exercise this year. I bought a gym subscription this year,
but unfortunately, that became my worst financial decision in the last several
years because I left Bengaluru before the government imposed the lockdowns.
However, I did some light exercise at home. That didn&apos;t do wonders, but at least
I was able to keep my BMI constant throughout the year. Even after eating
delicacies prepared by Mom all year!!! 😍 Hopefully, I will be able to start
running in 2021, even if only on weekends.&lt;/p&gt;
&lt;p&gt;In November, I suffered from severe back pain. After getting an ergonomic chair,
things seem to be in control. But that incident reminded me of the importance of
exercise. I will try to include some simple back exercises in 2021.&lt;/p&gt;
&lt;h1 id=&quot;family&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#family&quot;&gt;Family&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The year 2020 was quite an unusual year on this front. Since I started at NITC
in July 2014, I have been away from my family for most years. But thanks to
lockdown, I got to spend time with my family this year. I had anticipated
lockdowns in India quite early, so I left Bengaluru in March just before the
government imposed lockdowns in a &quot;shock and awe&quot; manner. So I reached home on
time, and that was the best decision I have taken this year. If not for my
family, I don&apos;t think I would have been able to handle pandemic-induced health
issues.&lt;/p&gt;
&lt;p&gt;I have been away from my brother for almost seven years now. More importantly,
these seven years were the life-defining years for both of us. It turns out that
he and I think very differently. I guess that our thinking results from the
different environments where we spent our early adulthood. It was initially very
tough to agree on something, but we slowly learned to agree to disagree. Staying
away from family has made me more careful and risk-averse in some sense. I tend
to (over) analyze everything, and that causes delays in decision making. On the
other hand, he is quite free-minded and rebellious. How different we both have
turned out to be!!!&lt;/p&gt;
&lt;p&gt;I don&apos;t mind this variety, though.&lt;/p&gt;
&lt;h1 id=&quot;reading&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#reading&quot;&gt;Reading&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I had set a target to read 20 books this year. In the end, I managed to read a
lot more than 20. Mid-year, Around July/August, I started losing track of the
books I was reading. As I mentioned in my last year&apos;s review, I was getting
disillusioned with Goodreads for some time. This year I tried to use it, but
ultimately I didn&apos;t log the majority of my reading anywhere. I don&apos;t know if
this is a good thing to do. I will try to keep it this way for some more time
and then analyze the data-collection pros and cons.&lt;/p&gt;
&lt;p&gt;I have identified some issues with my reading pattern. I tend to read the books
passively. That makes it quite challenging to retain knowledge for the long
term. On top of that, I don&apos;t make notes as well. So, I cannot even revise the
content quickly without going through the whole book again, which is
counter-productive. It is a childhood habit, and I assume it will be tough to
break this habit. However, whenever possible, I now actively remind myself to
question the book and not take everything written in the book for granted. It
will take some time (perhaps years), but I am confident about changing this
tendency.&lt;/p&gt;
&lt;p&gt;I read a variety of books this year. Most of these books were related to
humanities subjects like political science, history, etc. I got interested in
tech quite late in my life. Before that, humanities was my favorite pastime.
Once I entered the tech field, I somehow couldn&apos;t continue this. But this year,
I found myself distancing from technical topics somewhere around June. There is
a reason behind that disinterest that I would like to keep private for now. At
the same time, I struggled with my health issues, so I decided to start with
humanities again. Looking back at that decision, I feel it was a superb choice.
I have learned so much about India, its history, and the present. Somehow, I was
able to ask questions about why a particular thing was done the way it was done.
I was never able to think like that while reading a technical book. Does that
make my knowledge about tech hollow? I don&apos;t know yet. But I will be actively
looking for an answer in the coming times.&lt;/p&gt;
&lt;p&gt;One subject, where I expected to glide through was Economics. I
&lt;a href=&quot;https://yashagarwal.in/notes/2018-year-in-review/#reading&quot;&gt;mentioned&lt;/a&gt; in my 2018 review that I find
Economics interesting and want to learn more about it. I couldn&apos;t do that in
2019, but this year I decided to pursue that goal. So I started with the most
fundamental books - NCERT class 12th Microeconomics and Macroeconomics. The
result is that I have lost my interest in learning economics now (hopefully
temporarily). Either the books are written horribly, or I didn&apos;t put enough
effort. It took me ages to complete these two books, and still, I don&apos;t
understand a lot of the concepts. I think it was the wrong strategy to start
with these books. I should have watched video lectures by some University
professors. Perhaps I will do that this year, whenever I get time from my other
goals.&lt;/p&gt;
&lt;p&gt;Another subject, which caught my interest was Anthropology. I had
&lt;a href=&quot;https://highlights.yashagarwal.in/posts/2019-02-16-sapiens/&quot;&gt;read&lt;/a&gt; the
excellent &quot;Sapiens&quot; book by Yuval Noah Harari a couple of years back, and that
was a thought-provoking read for me. So I decided to read further on the topic
to answer some of the questions that I had about human society and why certain
cultural elements got evolved in the way they are at present. It is quite an
interesting subject, specifically social and cultural anthropology.&lt;/p&gt;
&lt;p&gt;Below are some of the superficial statistics about the books that I read this
year -&lt;/p&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Year Goal&lt;/th&gt;&lt;th&gt;Achieved&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Read/to-read&lt;/td&gt;&lt;td&gt;20&lt;/td&gt;&lt;td&gt;69&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Numpages&lt;/td&gt;&lt;td&gt;7000&lt;/td&gt;&lt;td&gt;16279&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;pages/day&lt;/td&gt;&lt;td&gt;19.13&lt;/td&gt;&lt;td&gt;44.48&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;days/book&lt;/td&gt;&lt;td&gt;18.30&lt;/td&gt;&lt;td&gt;5.30&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;book/month&lt;/td&gt;&lt;td&gt;1.67&lt;/td&gt;&lt;td&gt;5.75&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Once again, these numbers are not accurate indicators of the quality of reading.
Not all of the books were worth reading. I consider around 25 of these books as
a waste of my time. Some books were as small as 100 pages, while some were so
good that I wanted more even after reading 800+ pages.&lt;/p&gt;
&lt;p&gt;Now, the question is how many of these books benefited me. I plan to reread some
of these books and prepare some notes after/along with the second reading. I
have tried writing on paper, but my perfectionistic tendencies stop me from
&quot;spoiling&quot; the paper. So I will make the notes on Onenote this time and write
them down on paper later. Rewriting on paper is a compulsion because my mind
seems to be having issues recalling digitally-read content. It is one reason why
my Kindle is inside my drawer for a very long time.&lt;/p&gt;
&lt;p&gt;One of my wishes for 2021 is to read
&lt;a href=&quot;https://www.goodreads.com/book/show/78159.The_Story_of_Civilization&quot;&gt;The Story of Civilization&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;blogging-and-writing&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#blogging-and-writing&quot;&gt;Blogging and Writing&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;It is quite evident from this blog&apos;s activity in 2020 that I didn&apos;t write very
actively. I am going through a challenging phase (imposter syndrome?) in my tech
journey that is difficult to describe. I started this blog when I was actively
learning new things in tech. But now, I have almost hit a plateau. If I phrase
it in another way, I am not learning enough technical content now. I don&apos;t think
it is related to my work, but somehow, my attention has been on other things
lately.&lt;/p&gt;
&lt;p&gt;I have not been able to write anything on paper as well. I did some analysis on
this issue, and it turns out that I have perfectionist tendencies, as I
mentioned in the last section. I try to do everything with perfection, and that
doesn&apos;t work most of the time. You can&apos;t always have everything perfect in real
life, although aiming for perfectionism is not a bad thing. But when this goal
becomes the process, it starts creating problems. And I am facing the same
issue. Now, whenever I sit to write anything, I remind myself at regular
intervals that I don&apos;t have to be perfect all the time. It seems to work till
now.&lt;/p&gt;
&lt;p&gt;Anyway, in 2021, I will write a lot on paper and perhaps on this blog. I am
still contemplating if I should write long-form essays on some contemporary
issues on this blog. Maybe I will create a new WordPress blog for that kind of
stuff and keep this blog for my technical content and everyday life-related
posts.&lt;/p&gt;
&lt;p&gt;I figured out one more issue with my thought process. Given a topic, if you ask
me to write a summary of it, I wouldn&apos;t be able to articulate my thoughts.
Something that Richard Feynman was very good at. In other words, I struggle in
explaining my knowledge to others. I guess this means that I don&apos;t understand
the topic well enough to write anything about it. It might also mean that I have
some issues in thinking clearly. I hope, with practice, more active reading, and
regular writing practice, I will win over this issue.&lt;/p&gt;
&lt;h1 id=&quot;work&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#work&quot;&gt;Work&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;It isn&apos;t easy to summarise my work experience. It&apos;s my third year at Cisco now.
The team in which I was working for the last two years got dissolved. However,
higher management was quite helpful in transitioning to a new team working on
Snort development. So, I will be getting a much-needed product development
experience now. Till now, all is good; however, product development is slightly
weird. I need to give it more time before drawing any conclusions. Since I have
joined the new team, I feel that my day-to-day learning has suffered during work
hours. I hope it is a temporary phenomenon and I would be able to overcome it
soon.&lt;/p&gt;
&lt;p&gt;The COVID outbreak has spoiled some of my plans, and I am unsure if my familial
circumstances would allow me to opt for those plans in the near future. I
reoriented my goals to adjust to the changing conditions. But whatever happens,
I will try to utilize the available resources to the maximum extent possible.
Hopefully, everything will settle in the right place soon.&lt;/p&gt;
&lt;h1 id=&quot;media-consumption&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#media-consumption&quot;&gt;Media Consumption&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I seem to have been able to conquer the addiction to social media. I had been
trying to do this for 3-4 years, and this year, I feel that I was in control for
most of the time. Whenever I lost myself in Twitter/Quora/Reddit, I found it
easy to cut-off myself from these websites without any withdrawal symptoms,
which is a very pleasing experience.&lt;/p&gt;
&lt;p&gt;Facebook deserves a special mention here. I have been entirely out of touch with
Facebook for the last couple of years, partly due to self-control and partly due
to the bad press Facebook has recently gotten. One thing that has helped me is
that I don&apos;t have any content on my newsfeed because I took some time to
unfollow everyone. As there is no content to scroll, I don&apos;t feel the urge to
stay longer on the website. I log in occasionally to the website just for
checking the notification and friend requests.&lt;/p&gt;
&lt;p&gt;Coming to the media content consumed by me, these are the movies that I watched
this year. I did a lousy job logging this stuff, so this data is not
comprehensive. Of course, I watched a lot more movies than this.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/movies_watched.DLa0pJ-d_1xVpb3.webp&quot; alt=&quot;Movies in 2020&quot; title=&quot;Movies in 2020&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1926&quot; height=&quot;262&quot;&gt;&lt;/p&gt;
&lt;p&gt;I watched many web series during the July-October period. I can recall a few
right now - Sacred Games 1 and 2, She, Flesh, Bard of Blood, Mirzapur 1 and 2,
The Witcher, Sex Education, and Paatal Lok. In short, I wasted a lot of time
watching useless content. Sensory satisfaction, peer pressure, and the urge to
run away from my boredom are to blame for this binge-watching time.&lt;/p&gt;
&lt;p&gt;I am using &lt;a href=&quot;https://letterboxd.com/yagr/&quot;&gt;Letterboxd&lt;/a&gt; to log the movies, but
there does not seem to be a &lt;em&gt;free&lt;/em&gt; service that offers both movies and web
series logging. I wish somebody will make one in 2021.&lt;/p&gt;
&lt;p&gt;I use an Android phone and use Digital Wellbeing to monitor my phone usage.
Unfortunately, I can&apos;t export my usage data from the Digital Wellbeing app. This
data gets lost because I switch ROMs frequently. However, according to my
liberal estimate, I was able to keep my per day phone usage under 4 hours on
most of the days. There were some outliers, but mostly, my phone addiction was
relatively under control. However, I would have liked to keep it around 3 hours
per day.&lt;/p&gt;
&lt;h1 id=&quot;what-in-2021&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#what-in-2021&quot;&gt;What in 2021?&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This section is a new addition to this year&apos;s review. I usually don&apos;t set
explicit targets and certainly don&apos;t share them in public. So this is something
different. I am sharing my goals here. I will take this as a benchmark when I
sit to write my year review for 2021. I am hoping for at least a 60% success
rate.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Publish six long-form essays&lt;/strong&gt; - The plan is to learn the skill of
articulating thoughts. I don&apos;t have any particular topic in mind. Perhaps a
mix of History, Political Science and Tech. It can be in the form of essays or
an explanatory post, or anything else. Ideally, every two months.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read five fiction books&lt;/strong&gt; - To learn how other people write fantasy. I hope
to be able to read it for learning, not just for fun. You can follow my
progress &lt;a href=&quot;https://www.goodreads.com/user/show/63354397-yash&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sleep at proper times&lt;/strong&gt; - Now that majority of my work meetings are expected
to get scheduled during IST, I will try to sleep by 10 PM and sleep for at
least 8 hours every day. I am aiming for an 80% success rate in this aspect.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phone Usage&lt;/strong&gt; - Keep it under 3.5 hours per day (Aiming for 80% success)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write a Journal&lt;/strong&gt; - I have tried it earlier also but failed. This year, I
will try to document only important events in my life. At least once a month
should be good enough. The more the merrier!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Regular exercise&lt;/strong&gt; - I need to reduce my BMI to 22 from 23.3. That requires
me to shed at least 4 kgs of weight.
&lt;ul&gt;
&lt;li&gt;Weekend running (Aiming to do it on 50/104 weekends, accounting for winters)&lt;/li&gt;
&lt;li&gt;Mild 15-minute exercises at home two days a week (Aiming for 80% success)&lt;/li&gt;
&lt;li&gt;Meditation on the two days of the week (Aiming for 90% success)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;██████ (redacted) - I want to achieve this one badly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: A number of these goals depend on how many more months I get to spend
at home, after June.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;2020 was quite a year. I hope humanity has learned its lessons. While
industrialization and globalization have brought us a couple of hours away from
each other, it has become equally easy for pathogens and germs to travel and
reach farther ends of the world. I like to equate this situation to the
disease-carrying Europeans who went to the Americas in the 17th century. Nations
could practice some carefulness and proactivity in dealing with such problems.
It is not the last pandemic to ravage the world, for sure.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I expect to achieve some of my goals in 2021, but I won&apos;t deny a potential role
of luck or chance (whatever you like to call it). Hopefully, the gods of chance
will be on my side.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title>Two Years at Cisco</title><link>https://yashagarwal.in/notes/two-years-at-cisco/</link><guid isPermaLink="true">https://yashagarwal.in/notes/two-years-at-cisco/</guid><description>Reflecting on two years at Cisco, sharing key learnings on ownership, DevOps, communication, and innovation from my first corporate role.</description><pubDate>Wed, 16 Sep 2020 16:33:46 GMT</pubDate><content:encoded>&lt;p&gt;I completed two years at Cisco in August recently. I think it is a good time to
jot down my learnings and experiences from the past two years. It was my first
corporate job; however, I did not land up in a typical software development job.
Hence, my experiences are quite different and unique in a sense.&lt;/p&gt;
&lt;p&gt;I joined Cisco in 2018. As it usually happens with university recruits, I was
also randomly assigned to a team in the Office of CTO in Security Business Group
(SBG) in Cisco. I got assigned to a non-product team that worked in a
semi-research environment to develop PoCs demonstrating the integration of
future-looking technologies with the existing Cisco portfolio. The nature of
this work gave me some exciting skills and exposure to latest trends in
industry, but it came with its own set of disadvantages. I will discuss some of
them at the end of this article.&lt;/p&gt;
&lt;h1 id=&quot;take-ownership-of-your-work&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#take-ownership-of-your-work&quot;&gt;Take Ownership of your work&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Every member worked on a reasonably independent project in my team, directly
supervised by a Principal Engineer or a Technical Lead. Most of my superiors
(including my manager) were located in the USA, so there were many early-night
meetings involved. This also meant that nobody watched (micromanaged 🙊) me, and
I was given quite a bit of autonomy. I really appreciate this aspect.&lt;/p&gt;
&lt;p&gt;I learned how to come out of a problem when there is nobody to help or guide
you. Of course, I asked for help whenever needed; the freedom I enjoyed at work
was unparalleled.&lt;/p&gt;
&lt;p&gt;During two years, there were many occasions when some of my design and
development choices were questioned. I successfully defended some of them and
had to change the others. In the process, I learned the caveats in my
understanding and the importance of others&apos; perspectives while solving difficult
problems.&lt;/p&gt;
&lt;h1 id=&quot;developers-should-have-experience-with-operations&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#developers-should-have-experience-with-operations&quot;&gt;Developers should have experience with operations&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;As I mentioned above, most of my projects were individual projects. Naturally,
the responsibility of setting up and maintenance of the build-environment also
fell on my shoulders. My experience with Linux system administration from
college time came to my rescue here. In the process, I learned how invaluable
the skills of DevOps can be for a developer.&lt;/p&gt;
&lt;p&gt;There is a lot that I don&apos;t know yet, but my basics have grown strong enough to
grasp any new technology in a reasonable amount of time over the past two years.&lt;/p&gt;
&lt;h1 id=&quot;communications&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#communications&quot;&gt;Communications&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I have never been a good speaker, and talking to strangers has been one of my
weakest skills. After joining Cisco, this aspect of my personality has changed
considerably. Attending regular meetings and speaking about my ideas and work
gave me confidence. There are still some caveats with my public speaking skills.
I hope that I would be able to overcome these challenges with more experience.&lt;/p&gt;
&lt;h1 id=&quot;innovation&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#innovation&quot;&gt;Innovation&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The industry provides you access to the best minds in your field. You get to
meet wise people working and using their knowledge and expertise to generate
ideas that can change the world (or at least the industry). It motivates you to
compete with them. Although I have been unable to generate any patentable idea
in the past two years, I have been invited to participate in the discussions,
which led to patent applications. My biggest takeaway from these discussions was
that breadth is more useful than depth when it comes to idea generation. Knowing
various fields and connecting two seemingly different domains is a skill whose
importance cannot be overemphasized.&lt;/p&gt;
&lt;p&gt;Another thing I learned is that aiming for perfection doesn&apos;t help anyone. To
keep waiting for that best idea to pop up in your mind is illusionary and will
never happen. I have been a victim of this tendency to perfectionism the whole
of my life. For the past couple of months, I have been actively trying to avoid
this habit. My inconsistency in regularly writing on this blog can also be
attributed to my search for the &lt;em&gt;ideal&lt;/em&gt; blog post.&lt;/p&gt;
&lt;p&gt;In my opinion, quantity is better than quality. The same is true with the
generation of ideas. If you keep waiting that you will get the ultimate idea one
day, believe me, it will never happen.&lt;/p&gt;
&lt;h1 id=&quot;take-a-step-back--rethink&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#take-a-step-back--rethink&quot;&gt;Take a step back &amp;#x26; rethink&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;It happened quite a few times that I started looking for a solution to a problem
in one direction. After spending a considerable amount of time, I figured out
that the direction was wrong or worse, my understanding of the problem was
wrong. In such situations, it is better to backtrack and think again. It also
helps to ask someone for help. Sometimes, others can give you a different
perspective that you might not be able to see.&lt;/p&gt;
&lt;h1 id=&quot;dont-hesitate-to-brag-about-yourself&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#dont-hesitate-to-brag-about-yourself&quot;&gt;Don&apos;t hesitate to brag about yourself&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;When I joined Cisco, my colleagues suggested me to set up 1-1 with my manager to
stay in touch with him and showcase my work. I hesitated. I thought that what is
the point of talking about my work when it is visible to everybody through
weekly meetings. Now I understand, it is such a crucial step which shouldn&apos;t be
ignored at all. Keep a &lt;a href=&quot;https://jvns.ca/blog/brag-documents/&quot;&gt;brag&lt;/a&gt; document and
use it to keep records of your work, achievements, and accomplishments. I never
needed it till now, but I plan to use it in the future.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Coming to downsides, I have only one qualm. As I mentioned above, my team was
not a product team. So I missed out on some of the necessary product development
experience. I believe that having some experience developing and shipping
production-ready code is an absolute requirement to move towards my career
goals. Thankfully, I have switched my team now, and now I will be working on a
full-fledged security offering of Cisco.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;So, these are some of my insights from the past two years at Cisco. I want to
share a lot of other thoughts, but their time hasn&apos;t come yet. I will definitely
share more of these as I spend more time in the industry and tech.&lt;/p&gt;</content:encoded></item><item><title>Cassandra - A Decentralized Structured Storage System</title><link>https://yashagarwal.in/notes/cassandra-a-decentralized-structured-storage-system/</link><guid isPermaLink="true">https://yashagarwal.in/notes/cassandra-a-decentralized-structured-storage-system/</guid><description>A technical overview of Cassandra&apos;s architecture, data model, and distributed system principles, including routing, partitioning, and replication.</description><pubDate>Fri, 08 May 2020 01:51:55 GMT</pubDate><content:encoded>&lt;p&gt;Cassandra is a distributed storage system that can spread over thousands of
nodes and store terabytes of structured data. Cassandra was developed at
Facebook to solve performance issues during searches in Facebook Inbox.
Cassandra can provide a highly available service without a single point of
failure.&lt;/p&gt;
&lt;p&gt;Cassandra borrows some of its architecture choices from Google&apos;s
&lt;a href=&quot;https://static.googleusercontent.com/media/research.google.com/en//archive/bigtable-osdi06.pdf&quot;&gt;BigTable&lt;/a&gt;
and Amazon&apos;s
&lt;a href=&quot;https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf&quot;&gt;Dynamo&lt;/a&gt;.
In some ways, Cassandra resembles the traditional databases, yet it does not
support the relational data model completely.&lt;/p&gt;
&lt;h1 id=&quot;data-model&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#data-model&quot;&gt;Data Model&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Cassandra uses a tabular data structure like relational databases. A table in
Cassandra is a distributed multi-dimensional map indexed by a key. Every row
operation is atomic per replica, no matter how many columns are being read or
written into. Cassandra groups columns into sets called column family. A column
family is of two types - Simple and Super (column family within column family).
Cassandra can sort columns using name or time. Time-based sorting is useful when
used in a setting like Inbox searches where most recent messages should be
displayed first.&lt;/p&gt;
&lt;p&gt;Cassandra provides following methods -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;insert(table, key, rowMutation)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt;ser&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;ab&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;ey&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;ro&lt;/span&gt;&lt;span&gt;wM&lt;/span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;get(table, key, tableName)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;ab&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;ey&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;ab&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;am&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;delete(table, key, tableName)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;ab&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;ey&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;ab&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;am&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;architecture&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#architecture&quot;&gt;Architecture&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;A data storage system should satisfy some requirements - data persistence,
scalability, membership, failure detection and handling, data partitioning,
request routing, among others. Cassandra uses a variety of techniques to solve
these issues.&lt;/p&gt;
&lt;h2 id=&quot;routing&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#routing&quot;&gt;Routing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Any node can attend an incoming read/write request with a key. Each node in the
Cassandra cluster knows about other nodes. The serving node uses this
information and the request&apos;s key to determine the route of the request to the
appropriate node.&lt;/p&gt;
&lt;p&gt;In the case of write requests, the system routes the request to all replicas and
waits for a quorum of replicas to acknowledge the completion of the writes.&lt;/p&gt;
&lt;p&gt;For reads, the system either routes the requests to the nearest replica with
required data or forwards the request to all the replicas and waits for a quorum
of responses before replying. Which method, the system utilizes, depends on the
consistency requirements of the client.&lt;/p&gt;
&lt;h2 id=&quot;partitioning&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#partitioning&quot;&gt;Partitioning&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cassandra uses
&lt;a href=&quot;https://en.wikipedia.org/wiki/Consistent_hashing&quot;&gt;consistent hashing&lt;/a&gt; with an
order-preserving hash. The consistent hash function is used to hash the data key
to generate identifiers. The output range of the hash function is treated as a
ring (the largest hash value generated wraps around the smallest hash value).
Each node is assigned a random hash, which becomes its position on the ring.
Each node is responsible for the region in the ring between it and its
predecessor node.&lt;/p&gt;
&lt;p&gt;For each data item with a key, its hash is generated using the key. The ring is
traversed clockwise, and the first node with the position hash value greater
than the item&apos;s hash value is assigned to the data item. This node is deemed the
coordinator of the key.&lt;/p&gt;
&lt;p&gt;However, consistent hashing can result in an imbalance in the load distribution
and non-uniformity of data distribution. Cassandra solves these issues by
periodically analyzing the load information in the ring and repositioning the
lightly loaded nodes on the ring to alleviate high load nodes.&lt;/p&gt;
&lt;h2 id=&quot;replication&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#replication&quot;&gt;Replication&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Each data item is replicated at &lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;N&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; nodes in the ring. As mentioned above, each
data item&apos;s key is assigned to a coordinator node, which is responsible for the
replication of data items falling within its range (the region between it and
its predecessor node). For fault tolerance, in addition to locally storing keys,
the coordinator node replicates these keys at the &lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;(N-1)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;N&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; replicas on the ring.
Replication policies such as Rack aware, Rack unaware, Datacenter aware are used
for this purpose.&lt;/p&gt;
&lt;h2 id=&quot;leader-election&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#leader-election&quot;&gt;Leader Election&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cassandra uses Zookeeper for leader election and fault tolerance. Whenever a new
node joins the cluster, it contacts the leader who tells them what ranges the
node is responsible for. The metadata about ranges of a node is cached locally
as well as on the Zookeeper instance.&lt;/p&gt;
&lt;h2 id=&quot;membership&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#membership&quot;&gt;Membership&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cassandra uses Scuttlebutt - an anti-entropy Gossip based protocol to
disseminate the membership information inside the ring. Whenever a new node
joins the system, it calculates a token for itself. This token is gossiped
around the cluster. That&apos;s how each node in the system knows about the
membership and positions of other nodes in the system.&lt;/p&gt;
&lt;h2 id=&quot;failure-detection&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#failure-detection&quot;&gt;Failure Detection&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Failure detection is a mechanism by which a node can locally determine if any
other node in the system is up or down. Cassandra uses a modified version of
&lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ϕ&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\phi&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;ϕ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;-Accrual Failure Detector. The basic idea is that the failure detection
module emits the suspicion level of a node instead of a binary up/down status.
This suspicion level is &lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ϕ&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\phi&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;ϕ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. The idea is to represent &lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ϕ&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\phi&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;ϕ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; on a dynamically
adjustable scale, which reflects network and load conditions at the monitored
nodes.&lt;/p&gt;
&lt;p&gt;Every node in the system maintains a sliding window of inter-arrival times of
gossip messages from other nodes in the cluster. The distribution of these
inter-arrival times is determined, and &lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ϕ&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\phi&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;ϕ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is calculated. Cassandra uses
exponential distribution as an approximation for determining &lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ϕ&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\phi&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;ϕ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. The
original &lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ϕ&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\phi&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;ϕ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;-Accrual Failure Detection Algorithm used Gaussian distribution.&lt;/p&gt;
&lt;h2 id=&quot;scaling&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#scaling&quot;&gt;Scaling&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Whenever a new node joins the system, its token is generated such that it falls
within the range of an existing heavily loaded node. This results in the new
node splitting the range of the old node. The old node transfers some of its
data to the new node using kernel-kernel copying techniques.&lt;/p&gt;
&lt;h2 id=&quot;local-persistence&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#local-persistence&quot;&gt;Local Persistence&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cassandra uses a commit log as well as an in-memory data structure to store the
data. Each write is first committed to the commit log. Only after successful
write into the commit log, the data is saved in the in-memory data structure.
When the in-memory data structure crosses a predefined threshold, it is dumped
to the disk along with an index file for fast lookups. A merge process runs
periodically to merge these disk files.&lt;/p&gt;
&lt;p&gt;A read operation first queries the in-memory store. If data is not found there,
then a disk lookup is required. To avoid looking into multiple files, a bloom
filter, summarizing the keys in the file, is also used. The bloom filter can
also be used to check the key existence.&lt;/p&gt;
&lt;p&gt;Paper Link:-
&lt;a href=&quot;http://www.cs.cornell.edu/Projects/ladis2009/papers/Lakshman-ladis2009.PDF&quot;&gt;Cassandra - A Decentralized Structured Storage System&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Epidemic/Gossip Protocols</title><link>https://yashagarwal.in/notes/epidemic-gossip-protocol/</link><guid isPermaLink="true">https://yashagarwal.in/notes/epidemic-gossip-protocol/</guid><description>Explore Epidemic/Gossip Protocols, their analogy to virus spread, and their crucial role in efficient data dissemination in distributed systems.</description><pubDate>Tue, 14 Apr 2020 03:08:15 GMT</pubDate><content:encoded>&lt;p&gt;Last week, while reading the book
&lt;a href=&quot;https://www.goodreads.com/book/show/34646879-designing-data-intensive-applications&quot;&gt;Designing data-intensive applications&lt;/a&gt;,
I came across the term &quot;Gossip Protocols.&quot; The title was quite intriguing; hence
I search for it on Google. It turns out that it is a communication protocol. It
is sometimes also called the &quot;Epidemic Protocol.&quot;&lt;/p&gt;
&lt;p&gt;We are facing an ongoing pandemic called COVID-19. The term &quot;Epidemic Protocol&quot;
caught my attention, and I started wondering how the knowledge of epidemics is
going to be useful in computer systems. It turns out; these protocols try to
emulate the spread of a virus to effectively communicate the information to all
nodes in a distributed network.&lt;/p&gt;
&lt;p&gt;A virus spread quickly and robustly. Our goal in a distributed system is to
spread the information/updates as quickly as possible without burdening the
network. The epidemic protocols try to bring these ideas from epidemiology to
distributed systems.&lt;/p&gt;
&lt;p&gt;I use both terms (Gossip and Epidemic) interchangeably in this post.&lt;/p&gt;
&lt;h1 id=&quot;analogy-to-a-real-epidemic&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#analogy-to-a-real-epidemic&quot;&gt;Analogy to a real epidemic&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Let&apos; take a close look at how a virus spreads. I&apos;ll explain it using a small
sample of five people. We assume that, initially, none of these people is
infected. Now, because of some external factors, one of these (say &lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;) got
infected with the virus. We say that &lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is &lt;strong&gt;&lt;em&gt;infected&lt;/em&gt;&lt;/strong&gt;, and the remaining
four people are &lt;strong&gt;&lt;em&gt;susceptible&lt;/em&gt;&lt;/strong&gt; to infection. &lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; followed the advice of
doctors and isolated itself from the group. Now we say that &lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is &lt;strong&gt;&lt;em&gt;removed&lt;/em&gt;&lt;/strong&gt;
(either because he has the infection, but is not spreading it, or because he is
recovered).&lt;/p&gt;
&lt;p&gt;Now, let&apos;s extend this analogy to a network. In a network, we have multiple
nodes. These nodes are classified using the terms – infected, susceptible, and
removed. The infected nodes try to spread some information by periodically
selecting some peer nodes from the network. If a node is susceptible, that is,
it does not know the said information, then after the selection and transmission
of information by an infected node, the susceptible node also gets infected and
starts spreading the information. A node is said to be removed, if it already
knows the said information, but is not spreading it because, for example, all
its peers already know the information, so there is no need to keep spreading it
– the so-called herd immunity).&lt;/p&gt;
&lt;h1 id=&quot;some-theory&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#some-theory&quot;&gt;Some theory&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The concept of the Gossip Protocol is not something new. The 1987
&lt;a href=&quot;https://dl.acm.org/doi/10.1145/41840.41841&quot;&gt;paper&lt;/a&gt; Epidemic algorithms for
replicated database maintenance is considered seminal on this topic. The Gossip
Protocols were initially used to maintain consistency in replicated databases
for efficient data communication. Later, these protocols found their usage in
other areas such as service discovery in a distributed environment and
maintaining node memberships as well.&lt;/p&gt;
&lt;p&gt;Usually, these protocols work as follows -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A node (&lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;) in the network randomly selects another node with which it wants
to share information. Here, the assumption is that each node in the network
either maintains a list of all the other nodes or gets the information from a
centralized server.&lt;/li&gt;
&lt;li&gt;On receipt of information, the receiving node (&lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;B&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;) processes the
information.&lt;/li&gt;
&lt;li&gt;In the next round of this process, both &lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;B&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; again select nodes
randomly and transmit the information.&lt;/li&gt;
&lt;li&gt;These steps repeat periodically until the information is disseminated to
every node in the network.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;methods&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#methods&quot;&gt;Methods&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;In the paper mentioned above, two schemes of epidemic protocols were analyzed -&lt;/p&gt;
&lt;h2 id=&quot;anti-entropy&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#anti-entropy&quot;&gt;Anti-entropy&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this scheme, a node &lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; randomly contacts a random partner &lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;q&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;q&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;q&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; from the
current population. The nodes &lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;q&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;q&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;q&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; engage in information exchange to
resolve any differences between them. The updates known to &lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; but not known to
&lt;span&gt;&lt;span&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;q&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;q&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;q&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; are transferred using different strategies (push, pull, and push-pull).&lt;/p&gt;
&lt;p&gt;As it turns out, anti-entropy requires significant network bandwidth, because it
needs to send the complete database contents to other nodes for resolving any
differences. There are many approaches, such as sharing checksums, Merkel trees,
maintaining a recent update list, etc. that can be used to reduce the bandwidth
requirements in the anti-entropy algorithm. These strategies allow the sending
node to know what updates the receiving nodes require to become consistent.&lt;/p&gt;
&lt;p&gt;It can be proven that this algorithm guarantees the eventual dissemination of
information. The number of updates sent in this scheme is not bounded, so there
is no termination.&lt;/p&gt;
&lt;p&gt;This scheme is equivalent to the SI model (simple epidemic) from epidemiology.
The term SI stands for susceptible-infected (same as explained above). A node is
always susceptible or infected.&lt;/p&gt;
&lt;h2 id=&quot;rumor-mongering&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#rumor-mongering&quot;&gt;Rumor mongering&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As the name suggests, this scheme works similarly to how rumors spread.
Initially, all nodes are ignorant of a rumor. When a node learns about some
updates, it becomes a &quot;hot rumor.&quot; While a node holds a hot rumor, it
periodically chooses another node at random and pushes the rumor to the other
site. When a node has tried to share a hot rumor with too many nodes that have
already seen it, the node stops treating the rumor as hot and retains the update
without propagating it further. Rumor-mongering requires very less network
bandwidth because it needs to send only recent updates to other nodes.&lt;/p&gt;
&lt;p&gt;The equivalent of this in epidemiology is the SIR model (complex epidemic),
which stands for susceptible-infected-removed. A node can be susceptible or
infected or removed.&lt;/p&gt;
&lt;p&gt;Because of the removal of nodes, the number of messages transmitted in this
algorithm is bounded. However, because of this, there is a slight chance that
some updates might not reach all nodes. So it does not guarantee eventual
consistency.&lt;/p&gt;
&lt;p&gt;There are two strategies to decide when a node should be removed -&lt;/p&gt;


&lt;p&gt;The analysis of gossip algorithms focuses on designing strategies on how to
select the best peer group to share the information with.&lt;/p&gt;
&lt;p&gt;If you want to get started with this topic, here I recommend some papers that
are quite fundamental when it comes to an understanding of how gossiping works:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://dl.acm.org/doi/10.1145/41840.41841&quot;&gt;Epidemic Algorithms For Replicated Database Maintenance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.distributed-systems.net/my-data/papers/2007.osr.pdf&quot;&gt;Gossiping in Distributed Systems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://archive.cone.informatik.uni-freiburg.de/pubs/rumor.pdf&quot;&gt;Randomized Rumor Spreading&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://research.cs.cornell.edu/projects/Quicksilver/public_pdfs/2007PromiseAndLimitations.pdf&quot;&gt;The Promise, and Limitations, of Gossip Protocols&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.inf.u-szeged.hu/~jelasity/dr/doktori-mu.pdf&quot;&gt;Gossip-based Protocols for Large-scale Distributed Systems&lt;/a&gt; -
Read the first chapter of this book to get a basic understanding of Gossip
protocols)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flopezluis.github.io/gossip-simulator/&quot;&gt;A gossip protocol simulator&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;P.S.&lt;/strong&gt; - This is my first attempt to read and summarize CS research papers. I
have intentionally covered only a small part (first few pages) of the paper
(first reference in the above list) here, as I am still figuring out the best
way to read and summarise. I am confident that with time and practice, I will
get better.&lt;/p&gt;
&lt;p&gt;If you find any scope of improvement in current content, please let me know
through email or comment box below.&lt;/p&gt;</content:encoded></item><item><title>2019 - Year in Review</title><link>https://yashagarwal.in/notes/2019-year-in-review/</link><guid isPermaLink="true">https://yashagarwal.in/notes/2019-year-in-review/</guid><description>A candid 2019 year in review, reflecting on personal setbacks, reading habits, health struggles, and the challenges of consistent writing.</description><pubDate>Tue, 31 Mar 2020 06:09:47 GMT</pubDate><content:encoded>&lt;p&gt;It has been three months since 2020 started. I was not able to keep up with my
yearly habit of posting year reviews due to some reasons. One primary reason
behind my negligence is my disinterest in writing on this blog. I felt that it
was because the old layout of this blog had been too recurrent for me. So, I
decided to fix that issue before thinking about writing.&lt;/p&gt;
&lt;p&gt;The year 2019 was not a great year for me on many fronts. It was a year that
reminded me of my limitations and brought me out of the bubble, that self-help
books created for me. In retrospection, I find that I started a lot of things,
with the intention of learning, but couldn&apos;t achieve any of the targets.&lt;/p&gt;
&lt;p&gt;Like, I structure these posts every year, I have divided this post too in many
sections. It makes it easier for me to focus on various aspects of my life in
the past year. I will start with the best parts of my life.&lt;/p&gt;
&lt;h1 id=&quot;reading&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#reading&quot;&gt;Reading&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I had decided to read 26 books in the year. I finished the year with 28 books.
Out of 12 months, I did not read any book in January, November, and December. I
finished two of the fiction series that I wanted to read for years - Harry
Potter, and Percy Jackson. These two books are the reasons that I was able to
finish 28 books in 9 months. It took me very little time to finish these book
series. Other books (mostly non-fiction) took me ages to complete.&lt;/p&gt;
&lt;p&gt;I am not sure if I am getting any value out of non-fiction books &lt;em&gt;right now&lt;/em&gt;. I
do not take notes and forget most of the lessons in a few days. Not sure if this
is the right strategy while reading such books. Hence I have decided that I will
reduce the number of non-fiction books &lt;em&gt;for some time&lt;/em&gt; and put more attention to
technical publications and CS books.&lt;/p&gt;
&lt;p&gt;Though I am confident that my note-taking skills will not help in reading
technical books either, I do hope to improve over time.&lt;/p&gt;
&lt;p&gt;One of my reading goals from last year was to read a research paper every 15
days. I succeeded in the first quarter of the year and failed miserably after
that. I started with a good intention and kept reading for some months. Then
self-doubts began popping out. &lt;em&gt;What value am I getting out of this?&lt;/em&gt;, was the
question in my mind. I started this exercise because I have specific goals in my
mind, and I wanted to improve myself academically. But when you are not able to
answer such a question even to yourself, then something is wrong.&lt;/p&gt;
&lt;p&gt;This failure has taught me some crucial lessons. I tend to start things without
thinking about the end goal. It is the right approach when &lt;em&gt;learnings&lt;/em&gt; from the
process is more important than the result. But I was not able to focus on either
of them. I lost my focus when I realized this.&lt;/p&gt;
&lt;p&gt;I have come to understand the value of proper note-taking. I have read so many
good books, but I do not remember any lessons from these books, because -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I read passively and try to finish the book as quickly as possible.&lt;/li&gt;
&lt;li&gt;I did not try to implement the lessons in my day to day life while reading.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I lost my interest in reading news and blog articles also. I lost my interest
from social media and, in general, the Internet entirely. I preferred to sleep
as much as possible. That has its side-effects. Read on.&lt;/p&gt;
&lt;h1 id=&quot;blogging-and-writing&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#blogging-and-writing&quot;&gt;Blogging and Writing&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I had decided to write regularly in 2019. I didn&apos;t. It seems that failing was a
norm for me in 2019. This section was my worst hit interest in 2019. Somehow, I
was not able to gather the concentration required for writing. I used to get
sudden motivations for a few days, I wrote during those periods. The rest of the
time, I just thought that I should write. I think I suffered from the so-called
&lt;em&gt;Writer&apos;s Block&lt;/em&gt;.&lt;/p&gt;
&lt;h1 id=&quot;health&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#health&quot;&gt;Health&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;My analysis says that all my failures last year can be traced to this section. I
was sick for almost a quarter of the year. Repeatedly getting ill and the time
required for recovery took a toll on my body and mind. I lost all my focus and
will power to do anything.&lt;/p&gt;
&lt;p&gt;The exercise was again an issue. I certainly put more effort than last year, but
that effort was scattered throughout the year, for small periods. So, I do not
notice much difference. However, I continued to walk whenever I got time.&lt;/p&gt;
&lt;h1 id=&quot;work&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#work&quot;&gt;Work&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;It was not a very exciting year on the work front. I continued to work in Cisco
this year. The work was neither very interesting nor very dull. The nature of my
job is such that the exciting work shows up from time to time. With no fixed
deadlines and no fixed way of doing things, it can be quite satisfying and quite
frustrating at times.&lt;/p&gt;
&lt;h1 id=&quot;social-media&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#social-media&quot;&gt;Social Media&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I lost my interest in social media altogether. I opened Facebook only to see the
notification once in a while, sometimes after months. I got disillusioned by
Twitter this year, because of the toxic political content there. I was never a
regular user of YouTube anyway, so that was never a concern. However, I went to
great lengths to delete every Google app from my phone, especially Gmail and
YouTube. The email had become a new Facebook for me. I was checking emails every
15 minutes. So I signed out of Google account in my primary browser and
restricted my email activities to a secondary browser. It helped me in keeping
the urge to check email in control.&lt;/p&gt;
&lt;p&gt;But this sudden disinterest has created a void in my typical day, which is quite
reasonable given how much my life depends on the Internet. I am yet to figure
out how to fill this void. Reading books did not help, however sleeping and
watching movies helped for sure (however, not without its own set of problems).&lt;/p&gt;
&lt;h1 id=&quot;travel&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#travel&quot;&gt;Travel&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I was somewhat dissatisfied with myself for not traveling enough. This year, I
had decided to travel extensively. But my health betrayed me. Out of 365 days, I
was able to take the time of 4 days for travel. I went to Coorg and Chikmagalur
with friends. Both trips happened during the wrong weather conditions. But the
circumstances were such that I could not deny to my friends.&lt;/p&gt;
&lt;h1 id=&quot;miscellaneous&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#miscellaneous&quot;&gt;Miscellaneous&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;My daily routine, more or less, remained the same. Though I couldn&apos;t wake up
early in the morning most of the time, the reality is that I was not trying. My
only intention behind waking up early in the morning was to meditate. I did
that, however sporadically.&lt;/p&gt;
&lt;p&gt;One other goal in 2019 was to get rid of procrastination. I did not care about
it at all. Somehow, I was too busy fixing other issues in my life, that this
seemed like a minor problem. Anyway, I did not attempt to do anything on a
personal level, where procrastination would affect me. On the work front, at one
point or another, you have to work and show results. So there it was never
apparent. I tried many things to reduce the impact and influence of &lt;em&gt;technology&lt;/em&gt;
in my life. Although I consider myself successful to an extent, there is still
scope for improvement.&lt;/p&gt;
&lt;p&gt;In 2018, I was in full praise for to-do lists and the concept of maintaining
goals. 2019 has busted all those praises. This year, these techniques did not
work for me at all. Anyway, 2019 was one of those times when nothing worked for
me, so this failure does not come as a surprise to me. Though, I still believe
that this is something that can genuinely help me with some of my issues.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;If I had written this post at the beginning of the year 2020, I would have
written some wish for the year 2020 at this place, as I always do, but this time
is so gloomy that I am not able to think of anything good. I just pray to God
that everything gets all right soon.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Being with family during this time, has given me some mental stability. But, it
is also true that facing such circumstances and coming out triumphant, is what
shows the human character.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title>Automatic HTTPS Certs Using GoDaddy and Gitlab APIs</title><link>https://yashagarwal.in/notes/automatic-https-certs-using-godaddy-and-gitlab-apis/</link><guid isPermaLink="true">https://yashagarwal.in/notes/automatic-https-certs-using-godaddy-and-gitlab-apis/</guid><description>Learn how to automate HTTPS certificate renewal for your GitLab-hosted site using GoDaddy and Let&apos;s Encrypt, saving time and hassle.</description><pubDate>Tue, 23 Jul 2019 11:10:28 GMT</pubDate><content:encoded>&lt;p&gt;Before I start, here is some technical information about my website -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hosted on Gitlab and usage its CD for automatic deployment, which is triggered
on a git commit.&lt;/li&gt;
&lt;li&gt;The domain name registrar is GoDaddy.&lt;/li&gt;
&lt;li&gt;Let&apos;s Encrypt as the TLS certificate provider for my domain name.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&apos;s Encrypt provides certificates for 90 days only, so I was forced to set up
the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;certbot&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; every three months, then generate the certificate and &lt;em&gt;manually&lt;/em&gt;
deploy the certificates to GitLab. It was frustrating because in three months,
my shell probably will not remember the command I used last time, and I was too
lazy to document the process somewhere.&lt;/p&gt;
&lt;p&gt;Then I came across a &lt;a href=&quot;https://github.com/pallavagarwal07/NamesiloCert&quot;&gt;project&lt;/a&gt;,
which was trying to do a similar thing with other domain name registrar. I
thought that this is an excellent setup to adapt and modify it to suit my needs.
So I decided to write my module for automatic deployment of Let&apos;s Encrypt
certificates to GitLab.&lt;/p&gt;
&lt;h1 id=&quot;how-does-lets-encrypt-work&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#how-does-lets-encrypt-work&quot;&gt;How does Let&apos;s Encrypt work?&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Before Let&apos;s Encrypt can generate the certificate for the domain, it requires
the user to prove domain ownership. Let&apos;s Encrypt provides two
&lt;a href=&quot;https://letsencrypt.org/docs/challenge-types/&quot;&gt;methods&lt;/a&gt; to do this task -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Updating the DNS records of the domain registrar (DNS-01 challenge)&lt;/li&gt;
&lt;li&gt;Adding an HTTP resource under a well-known URI on the website (HTTP-01
challenge)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using the second method requires me to add a file on my website, and I did not
want to do that. Moreover, if in the future, I decide to host some other
service, which does not have a website, then this method will fail.&lt;/p&gt;
&lt;p&gt;The first method requires that the domain configuration on the domain registrar
is modified. GoDaddy provides a robust API, and it is not difficult to utilize
that API to automate specific tasks. The probability of changing the registrar
is quite low, at least for the next few years. It will be easier to generate the
certificates for any subdomains, as all the subdomains will also be hosted under
the same domain registrar.&lt;/p&gt;
&lt;h1 id=&quot;how-does-the-tool-work&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#how-does-the-tool-work&quot;&gt;How does the tool work?&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;So here are the steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Call &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;certbot&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; with all the domain names&lt;/li&gt;
&lt;li&gt;Invoke GoDaddy API to update the DNS records as indicated by Certbot&lt;/li&gt;
&lt;li&gt;Wait for 10 minutes for DNS changes to propagate&lt;/li&gt;
&lt;li&gt;Let &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;certbot&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; verify the DNS changes&lt;/li&gt;
&lt;li&gt;Use the GitLab API to deploy the generated certificates to GitLab pages&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;invoking-certbot&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#invoking-certbot&quot;&gt;Invoking certbot&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In step 1, we call &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;certbot&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; will the preferred method DNS. We also need to
supply an email id (used by Let&apos;s Encrypt to notify domain expiration). The
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;EMAIL_ID&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; environment variable can be used to store the email id of the user.&lt;/p&gt;
&lt;p&gt;Certbot runs in an interactive mode by default. It is not desired in a scripted
environment. Certbot also provides mechanisms to deploy the certificates to a
local server automatically, but as we are hosting our website on Gitlab, we do
not want the automatic deployment facility. So we need to invoke the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;certbot&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;
command with &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;--manual&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;certonly&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; modes.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;certbot&lt;/span&gt;   --manual \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;          --preferred-challenges&lt;/span&gt; dns \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;          --agree-tos&lt;/span&gt; \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;          --email&lt;/span&gt; &quot;${EMAIL_ID}&quot; \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;          --no-eff-email&lt;/span&gt; \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;          --expand&lt;/span&gt; \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;          --renew-by-default&lt;/span&gt; \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;          --manual-public-ip-logging-ok&lt;/span&gt; \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;          --noninteractive&lt;/span&gt; \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;          --redirect&lt;/span&gt; \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;          --config-dir&lt;/span&gt; ${DIR}/generated/config \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;          --work-dir&lt;/span&gt; ${DIR}/generated/work \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;          --logs-dir&lt;/span&gt; ${DIR}/generated/logs \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;          --manual-auth-hook&lt;/span&gt; ${DIR}/auth_hook.sh \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;          -d&lt;/span&gt; yashagarwal.in \
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;          certonly&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The explanation for most of the flags used in the above command can be found by
running the following command -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;certbot&lt;/span&gt; --help&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;--manual-auth-hook&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; flag is worth looking. This hook provides a mechanism
to specify the executable, which can be used to facilitate domain ownership
validation. In this case, the hook points to a script &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;auth_hook.sh&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, which then
calls a Go client, which interacts with GoDaddy API.&lt;/p&gt;
&lt;h2 id=&quot;adding-dns-entry-to-godaddy-dns-manager&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#adding-dns-entry-to-godaddy-dns-manager&quot;&gt;Adding DNS entry to GoDaddy DNS manager&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Certbot supplies two environment variables &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;CERTBOT_DOMAIN&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, which contains the
domain name to be verified and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;CERTBOT_VALIDATION&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, which includes a random
string corresponding to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;_acme-challenge TXT&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; entry. What this means is that, if
I have&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;CERTBOT_DOMAIN=yashagarwal.in&lt;/span&gt;
&lt;span&gt;CERTBOT_VALIDATION=6VNg5kDVI_BF1S9N5s74LTBHQnwDpQqKlblKRjIzBwM&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Then the DNS manager should contain a TXT entry &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;_acme-challenge.yashagarwal.in&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;
with the value of &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;6VNg5kDVI_BF1S9N5s74LTBHQnwDpQqKlblKRjIzBwM&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;auth_hook.sh&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file calls the Go client with the abovementioned environment
variables. The relevant code can be found
&lt;a href=&quot;https://github.com/yashhere/GoDaddy-GitLab-Certs/blob/master/auth_hook.sh&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once all the DNS entries are added, the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;auth_hook.sh&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; script will sleep for 10
minutes. It is to allow DNS changes to propagate throughout the Internet. It is
a random duration as I could not find any GoDaddy support page mentioning the
exact period used by them.&lt;/p&gt;
&lt;h2 id=&quot;generation-of-certificates&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#generation-of-certificates&quot;&gt;Generation of certificates&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;auth_hook.sh&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; script returns successfully, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;certbot&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; will verify the
DNS records. If the verification is successful, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;certbot&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; will generate the
certificates in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;./generated/config/live/{CERTBOT_DOMAIN}&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; directory.&lt;/p&gt;
&lt;h2 id=&quot;deploying-the-certificates-to-gitlab&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#deploying-the-certificates-to-gitlab&quot;&gt;Deploying the certificates to GitLab&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I use the following command to deploy the certificates to Gitlab pages where my
website is hosted -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;curl&lt;/span&gt;  -vvv \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;      --request&lt;/span&gt; PUT \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;      --header&lt;/span&gt; &quot;Private-Token:${GITLAB_TOKEN}&quot; \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;      --form&lt;/span&gt; &quot;certificate=@${key_dir}/fullchain.pem&quot; \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;      --form&lt;/span&gt; &quot;key=@${key_dir}/privkey.pem&quot; \ &quot;https://gitlab.com/api/v4/projects/yashhere%2Fyashhere.gitlab.io/pages/domains/yashagarwal.in&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;where&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;key_dir&lt;/span&gt;=&quot;./generated/config/live/yashagarwal.in&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Moreover, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;GITLAB_TOKEN&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is an environment variable that contains the API token
generated from the Gitlab settings page.&lt;/p&gt;
&lt;h1 id=&quot;automatic-deployment-using-travis-ci&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#automatic-deployment-using-travis-ci&quot;&gt;Automatic Deployment using Travis CI&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;It is not automation if I have to run this script manually every three months.
So I created a Travis CI job to automate this process. The job will run every
month and deploy my certificates automatically. It has been four months, and I
have not faced any issues with this setup.&lt;/p&gt;
&lt;p&gt;The code for this post can be viewed at
&lt;a href=&quot;https://github.com/yashhere/GoDaddy-GitLab-Certs&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for reading. Cheers 😄&lt;/p&gt;</content:encoded></item><item><title>Setting Up ModSecurity on Ubuntu</title><link>https://yashagarwal.in/notes/setting-up-modsecurity-on-ubuntu/</link><guid isPermaLink="true">https://yashagarwal.in/notes/setting-up-modsecurity-on-ubuntu/</guid><description>Secure your web applications with ModSecurity. This guide details setting up the open-source WAF and Core Rule Set on Ubuntu for robust protection.</description><pubDate>Mon, 01 Jul 2019 12:50:18 GMT</pubDate><content:encoded>&lt;p&gt;Recently, I am experimenting with Web Application Firewalls a lot. ModSecurity
is one of them. It is the most famous and useful open-source Web Application
Firewall (WAF) in existence. It is supported by various web servers such as
Apache, Nginx, and IIS.&lt;/p&gt;
&lt;p&gt;The job of ModSecurity is to sit in front of the application web server and
check the incoming requests and outgoing responses to filter out malicious
content. It does so by the use of powerful and complex regular expressions.
ModSecurity uses a rule language for its rules. The rule language has variables
and operators defined to aid in the process of parsing HTTP requests.&lt;/p&gt;
&lt;p&gt;ModSecurity, in itself, cannot block or allow requests. It is just a rule
engine. It requires rules to operate appropriately. That&apos;s where its sister
project, Core Rule Set (CRS), comes into the picture. CRS is a rule set
developed to be used with ModSecurity. It has been in active development for
several years now and is very mature. Together, ModSecurity and CRS form a
formidable defense against the widespread web application attacks.&lt;/p&gt;
&lt;p&gt;Now that you know, what a WAF is, let&apos;s proceed to install ModSecurity on
Ubuntu. I will be compiling ModSecurity&apos;s latest version on Ubuntu 18.04. We
will also configure ModSecurity to use Core Rule Set.&lt;/p&gt;
&lt;h1 id=&quot;installing-dependencies&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#installing-dependencies&quot;&gt;Installing Dependencies&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;ModSecurity requires some dependencies to work correctly. Let&apos;s install them -&lt;/p&gt;
&lt;p&gt;First, upgrade the Ubuntu system.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; apt-get -y update
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; apt-get -y upgrade&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now install the dependencies.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; apt-get -y install git libtool dh-autoreconf pkgconf gawk libcurl4-gnutls-dev libexpat1-dev libpcre3-dev libssl-dev libxml2-dev libyajl-dev zlibc zlib1g-dev libxml2 libpcre++-dev libxml2-dev libgeoip-dev liblmdb-dev lua5.2-dev iputils-ping locales apache2 apache2-dev ca-certificates wget&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;Optional&lt;/em&gt;: clean up the Ubuntu caches.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; apt-get clean &amp;#x26;&amp;#x26; sudo rm -rf /var/lib/apt/lists/*&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Install &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;SSDeep&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; as well (as done
&lt;a href=&quot;https://github.com/coreruleset/modsecurity-docker/blob/bf60dcb29fad101c5b90edf272909742e4e85929/v2-apache/Dockerfile&quot;&gt;here&lt;/a&gt;)&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;cd&lt;/span&gt; ~
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;git&lt;/span&gt; clone https://github.com/ssdeep-project/ssdeep
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;cd&lt;/span&gt; ssdeep
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;./bootstrap&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;./configure&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;make&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; make install&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;compiling-modsecurity&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#compiling-modsecurity&quot;&gt;Compiling ModSecurity&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Let&apos;s clone ModSecurity from Github.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;cd&lt;/span&gt; ~
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;git&lt;/span&gt; clone -b v3/master --single-branch https://github.com/SpiderLabs/ModSecurity
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;cd&lt;/span&gt; ModSecurity
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;git&lt;/span&gt; submodule init
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;git&lt;/span&gt; submodule update
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;./build.sh&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;./configure&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;make&lt;/span&gt;                # takes ~8 minutes on AWS t2.micro
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; make install&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;compiling-modsecurity-apache-connector&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#compiling-modsecurity-apache-connector&quot;&gt;Compiling ModSecurity-apache connector&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;To configure it with Apache, we will require ModSecurity-apache connector. Let&apos;s
install that as well.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;cd&lt;/span&gt; ~
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;git&lt;/span&gt; clone https://github.com/SpiderLabs/ModSecurity-apache
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;cd&lt;/span&gt; ModSecurity-apache
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;./autogen.sh&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;./configure&lt;/span&gt; --with-libmodsecurity=/usr/local/modsecurity
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;make&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; make install&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;setting-up-crs-rules&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#setting-up-crs-rules&quot;&gt;Setting up CRS rules&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Now, let&apos;s download CRS rule set as well.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;cd&lt;/span&gt; ~
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;git&lt;/span&gt; clone -b v3.2/dev https://github.com/SpiderLabs/owasp-modsecurity-crs
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; mv owasp-modsecurity-crs/ /usr/local/&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Rename CRS configuration file -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; mv /usr/local/owasp-modsecurity-crs/crs-setup.conf.example /usr/local/owasp-modsecurity-crs/crs-setup.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;setting-up-modsecurity&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#setting-up-modsecurity&quot;&gt;Setting up ModSecurity&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Now, we need to create a file in the Apache modules directory, so that Apache
can know, how to activate ModSecurity.&lt;/p&gt;
&lt;p&gt;Create &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/apache2/mods-enabled/security3.conf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file and paste the following
contents -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;apache&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;apache&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;LoadModule&lt;/span&gt; security3_module /usr/lib/apache2/modules/mod_security3.so
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;modsecurity &lt;/span&gt;on
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;modsecurity_rules_file &apos;/etc/apache2/modsec/main.conf&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;As you can see, the last line in the above code block reference a file
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;main.conf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; in a folder &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;modsec&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. This folder will not be present by default. We
need to create that.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; mkdir -p /etc/apache2/modsec&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Setup ModSecurity configuration file -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# enables Unicode support in ModSecurity&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; wget -P /etc/apache2/modsec/ https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/unicode.mapping
 
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; wget -P /etc/apache2/modsec/ https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/modsecurity.conf-recommended
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; mv /etc/apache2/modsec/modsecurity.conf-recommended /etc/apache2/modsec/modsecurity.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Change the SecRuleEngine directive in the configuration to change from the
default &quot;detection only&quot; mode to actively dropping malicious traffic.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; sed -i &apos;s/SecRuleEngine DetectionOnly/SecRuleEngine On/&apos; /etc/apache2/modsec/modsecurity.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Change the location of &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;modsec_audit.log&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file to Apache log directory.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; sed -i &apos;s/SecAuditLog \/var\/log\/modsec_audit.log/SecAuditLog \/var\/log\/apache2\/modsec_audit.log/&apos; /etc/apache2/modsec/modsecurity.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;To configure ModSecurity to use CRS rule set, put the following text in
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/apache2/modsec/main.conf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;apache&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;apache&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;Include&lt;/span&gt; &quot;/etc/apache2/modsec/modsecurity.conf&quot;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;Include&lt;/span&gt; &quot;/usr/local/owasp-modsecurity-crs/crs-setup.conf&quot;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;Include&lt;/span&gt; &quot;/usr/local/owasp-modsecurity-crs/rules/*.conf&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Also enable some Apache modules for better functioning of ModSecurity.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; a2enmod unique_id headers rewrite actions dav dav_fs&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now restart the Apache server&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; systemctl restart apache2&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;fixing-some-common-issues&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#fixing-some-common-issues&quot;&gt;Fixing some common issues&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Sometimes, I had encountered errors when ModSecurity was not able to append logs
to its log file. I figured out that ModSecurity did not have enough permissions
to write that file. We can fix this issue quickly.&lt;/p&gt;
&lt;p&gt;First, test if you really have this issue or not.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;$ curl &apos;http://localhost/?q=&quot;&gt;&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;script&gt;
&lt;span style=&quot;--shiki-dark:#DCBDFB;--shiki-light:#6F42C1&quot;&gt;  alert&lt;/span&gt;(1)
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;script&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&apos;&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;!&lt;/span&gt;DOCTYPE html PUBLIC &quot;-//IETF//DTD HTML 2.0//EN&quot;&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;head&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;title&gt;403 Forbidden&amp;#x3C;/title&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;/&lt;/span&gt;head&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;h1&gt;Forbidden&amp;#x3C;/h1&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;p&gt;You dont have permission to access / on this server.&amp;#x3C;br /&gt;&amp;#x3C;/p&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;hr /&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;address&gt;Apache/2.4.29 (Ubuntu) Server at localhost Port 80&amp;#x3C;/address&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;/&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;html&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now go to Apache log directory and check the contents of &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;modsec_audit.log&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;
file.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;cd&lt;/span&gt; /var/log/apache2
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;tail&lt;/span&gt; modsec_audit.log&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;You should see the following content -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;---0LzdyETA---A--&lt;/span&gt;
&lt;span&gt;[01/Jul/2019:14:42:41 +0000] 156199216179.666171 127.0.0.1 41824 ip-xxx-xx-xx-xx.ap-south-1.compute.internal 80&lt;/span&gt;
&lt;span&gt;---0LzdyETA---B--&lt;/span&gt;
&lt;span&gt;GET /?q=&quot;&gt;&amp;#x3C;script&gt;alert(1)&amp;#x3C;/script&gt; HTTP/1.1&lt;/span&gt;
&lt;span&gt;Host: localhost&lt;/span&gt;
&lt;span&gt;User-Agent: curl/7.58.0&lt;/span&gt;
&lt;span&gt;Accept: */*&lt;/span&gt;
 
&lt;span&gt;---TqjMwy7h---D--&lt;/span&gt;
 
&lt;span&gt;---TqjMwy7h---F--&lt;/span&gt;
&lt;span&gt;HTTP/1.1 403&lt;/span&gt;
 
&lt;span&gt;---TqjMwy7h---H--&lt;/span&gt;
&lt;span&gt;ModSecurity: Warning. detected XSS using libinjection. [file &quot;/usr/local/owasp-modsecurity-crs/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf&quot;] [line &quot;37&quot;] [id &quot;941100&quot;] [rev &quot;&quot;] [msg &quot;XSS Attack Detected via libinjection&quot;] [data &quot;Matched Data: XSS data found within ARGS:q: &quot;&gt;&amp;#x3C;script&gt;alert(1)&amp;#x3C;/script&gt;&quot;] [severity &quot;2&quot;] [ver &quot;OWASP_CRS/3.1.0&quot;] [maturity &quot;0&quot;] [accuracy &quot;0&quot;] [tag &quot;application-multi&quot;] [tag &quot;language-multi&quot;] [tag &quot;platform-multi&quot;] [tag &quot;attack-xss&quot;] [tag &quot;OWASP_CRS/WEB_ATTACK/XSS&quot;] [tag &quot;WASCTC/WASC-8&quot;] [tag &quot;WASCTC/WASC-22&quot;] [tag &quot;OWASP_TOP_10/A3&quot;] [tag &quot;OWASP_AppSensor/IE1&quot;] [tag &quot;CAPEC-242&quot;] [hostname &quot;localhost&quot;] [uri &quot;/&quot;] [unique_id &quot;156198848361.198287&quot;] [ref &quot;v8,27t:utf8toUnicode,t:urlDecodeUni,t:htmlEntityDecode,t:jsDecode,t:cssDecode,t:removeNulls&quot;]&lt;/span&gt;
&lt;span&gt;....&lt;/span&gt;
&lt;span&gt;....&lt;/span&gt;
 
&lt;span&gt;---TqjMwy7h---I--&lt;/span&gt;
 
&lt;span&gt;---TqjMwy7h---J--&lt;/span&gt;
 
&lt;span&gt;---TqjMwy7h---Z--&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;If you do not see the following content, and the file is empty or it does not
exist, then ModSecurity was not able to open this file for writing. Use the
following fix -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# find out the user, Apache is running as&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;apache_user&lt;/span&gt;=&quot;$(ps -ef | egrep &apos;(httpd|apache2|apache)&apos; | grep -v `whoami` | grep -v root | head -n1 | awk &apos;{print $1}&apos;)&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Add this user to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;adm&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; group which owns the Apache logs directory in Ubuntu.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; usermod -G adm www-data&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now, change the owner of Apache log directory to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;apache_user&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; chown -R $apache_user:$apache_user /var/log/apache2/*&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now, ModSecurity should be able to append logs to the file &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;modsec_audit.log&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;h1 id=&quot;bonus-enabling-json-logs&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#bonus-enabling-json-logs&quot;&gt;&lt;em&gt;Bonus&lt;/em&gt;: Enabling JSON logs&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Honestly speaking, I was not able to make it work every time. I do not
know what is the issue, but it works with some of the installations, and with
some of the installations, it just doesn&apos;t log anything to the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;audit&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;
directory. If anyone has managed to make it work consistently, please let me
know.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edit (13/07/2020):&lt;/strong&gt; The JSON logging works fine. The issue was that
ModSecurity did not have permission to create subdirectories in the Apache log
directory. I suppose it is something related to SELinux. However, a simple
solution is to add the user under which the Apache process runs to the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;adm&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;
group. It might not be the right solution security-wise. However, from a quick
remediation point of view, it works. Please let me know if you identify any
better solution to fix the problem.&lt;/p&gt;
&lt;p&gt;Anyway, if you are like me, who do not like the default ModSecurity log format,
ModSecurity provides an option to generate logs in JSON format as well. To
enable JSON support, the YAJL library should be installed. We already installed
this package when we were installing dependencies, so our ModSecurity setup is
compiled with JSON support. Let us now configure ModSecurity to generate JSON
logs.&lt;/p&gt;
&lt;p&gt;Open the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/apache2/modsec/modsecurity.conf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file and find the following
lines -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;apache&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;apache&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;SecAuditLogType           Serial&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;SecAuditLog               /var/log/modsec_audit.log&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Once you have found the following lines, replace these lines with the following
lines&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;apache&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;apache&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;SecAuditLogFormat         JSON&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;SecAuditLogType           Parallel&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;SecAuditLog               /var/log/apache2/modsec_audit.log&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;SecAuditLogStorageDir     /var/log/apache2/audit/&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;SecAuditLogFileMode       &lt;/span&gt;0644
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;SecAuditLogDirMode        &lt;/span&gt;0755&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Restart Apache server&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; systemctl restart apache2&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now, go to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/var/log/apache2/&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; directory and create &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;audit&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; folder.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; usermod -G adm $apache_user
 
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;cd&lt;/span&gt; /var/log/apache2
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; mkdir audit
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# make `apache_user` owner of this directory as well...&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; chown -R $apache_user:$apache_user /var/log/apache2/audit&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now, ModSecurity should be able to generate JSON logs in this directory.
ModSecurity generates logs in the following format -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;ubuntu@server:/var/log/apache2$&lt;/span&gt; tree audit
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;audit&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;└──&lt;/span&gt; 20190701
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;    ├──&lt;/span&gt; 20190701-1132
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;    │&lt;/span&gt;   ├── 20190701-113225-156196094515.868593
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;    │&lt;/span&gt;   └── 20190701-113226-156196094691.154769
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;    ├──&lt;/span&gt; 20190701-1211
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;    │&lt;/span&gt;   ├── 20190701-121122-156196328239.048942
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;    │&lt;/span&gt;   └── 20190701-121122-156196328243.018882
 
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;    ....&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;    ....&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now, your site should be relatively more secure than before.&lt;/p&gt;
&lt;h1 id=&quot;a-warning-though&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#a-warning-though&quot;&gt;A warning, though&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;CRS is known to generate a lot of false-positive when enabled completely. We
have not touched CRS paranoia levels. By default, it is set to paranoia level 1,
which is known to produce false positives rarely, but still, as a measure of
precaution, monitor your site&apos;s traffic for some time, and then decide if you
need to disable some of the CRS rules or not.&lt;/p&gt;</content:encoded></item><item><title>Travelogue - Chikmagalur</title><link>https://yashagarwal.in/notes/travelogue-chikmagalur/</link><guid isPermaLink="true">https://yashagarwal.in/notes/travelogue-chikmagalur/</guid><description>Journey through Chikmagalur during monsoon! Discover scenic drives, delicious food, and the intricate beauty of Sri Chennakeshava Temple.</description><pubDate>Sat, 29 Jun 2019 00:40:03 GMT</pubDate><content:encoded>&lt;p&gt;South India is blessed with nature throughout the year, but monsoons bring a
different flavor and ethereal quality to some places. Although the rainy season
might not be the best time to travel, there is a certain charm in holidaying
during the downpour.&lt;/p&gt;
&lt;p&gt;We (I and my flatmates in Bengaluru) were planning a trip to Chikmagalur since
the beginning of June. One of my friends knows driving, so we decided to rent a
car and drive ourselves to a distance of approximately 250 KMs. We booked the
car through Drivezy. They had promised a Mahindra KUV100, but at the last
moment, they couldn&apos;t keep their commitment and gave us a Honda Amaze with
automatic transmission. My friend who was driving had never driven such a car,
so we all got scared of our fate for the next two days, but we decided to go
ahead with it, trusting our friend.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I too know driving, but like every other aspect of my life, I never gained
enough confidence to go on such a long drive. It was a similar case this time as
well.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The way to Chikmagalur from Bengaluru is the well-maintained NH75 (it has a
total of four tolls, so maintenance is expected). We started early on the
morning of Saturday, 22nd June to avoid Bengaluru&apos;s traffic. Nature was
accommodating that day, and the Sun 🌞 stayed hidden behind clouds for most of
our journey. That made our 6-hour drive very enjoyable.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/bdiyaFI.Dt-j0ssT_Z2tHHPz.webp&quot; alt=&quot;Somewhere on NH75&quot; title=&quot;Somewhere on NH75&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4032&quot; height=&quot;3024&quot;&gt;&lt;/p&gt;
&lt;p&gt;We were not in any hurry and wanted to enjoy every moment of our trip to the
fullest. With Punjabi beats playing in our car, we stopped at various places on
the highway.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Chikmagalur means &quot;The town of the younger daughter&quot; in the Kannada. The town
is said to have been given as a dowry to the younger daughter of Rukmangada,
the legendary chief of Sakkarepatna and hence the name.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We stopped at Adyar Ananda Bhavan 🏨 for breakfast. I have tasted sweets from
A2B, and the taste was the best that I could get in the South. So I decided to
eat Masala Dosai and Idli Sambhar there. The food did not disappoint me at all.&lt;/p&gt;
&lt;p&gt;After breakfast, we resumed our journey. The first stop in our trip was the
gorgeous Sri Chennakeshava Temple. &lt;em&gt;Chenna&lt;/em&gt; means beautiful and &lt;em&gt;Keshava&lt;/em&gt; refers
to Lord Vishnu. That should give you an idea, the presiding deity of the temple
is the &lt;em&gt;Handsome Vishnu&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The whole premises of the temple is filled with sheer poetry on the walls in the
form of stone sculptures. I was completely mesmerized by its intricate but
aesthetically pleasing carvings.&lt;/p&gt;
&lt;p&gt;On the entrance of the temple, a vast golden Gopuram welcomes the devotees. I
was amazed by the level of details on the sculptures engraved on the Gopuram. My
phone&apos;s camera will not be able to do justice to this intricate artistry.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/V6AAfuv.RAVr84sq_1Io6Ap.webp&quot; alt=&quot;The Gopuram of Sri Chennakeshava Temple&quot; title=&quot;The Gopuram of Sri Chennakeshava Temple&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4032&quot; height=&quot;3024&quot;&gt;&lt;/p&gt;
&lt;p&gt;The one specialty of the main temple is that it does not feature a dome. I have
not seen any major Hindu temple without a dome over the idol of the main deity.
It seems like an aberration to me, but a welcoming one. A disclaimer, I am not
an architecture buff, so I do not know how correct my facts are here.&lt;/p&gt;
&lt;p&gt;The inside of the temple is pretty dark. There are several pillars inside the
temple. Each of the pillars is decorated with various types of sculptors.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/jhqoSTE.D_hmT6Sm_2evKsl.webp&quot; alt=&quot;A pillar inside the temple&quot; title=&quot;A pillar inside the temple&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;However, the fascinating thing is at the ceiling. The carvings done on the
ceiling of the temple is just amazing.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/074g3uO.DrTIuoks_Z28lowR.webp&quot; alt=&quot;The ceiling of the temple&quot; title=&quot;The ceiling of the temple&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4032&quot; height=&quot;3024&quot;&gt;&lt;/p&gt;
&lt;p&gt;As I mentioned above, I am not an architecture buff, so I would not be able to
write a lot about the architecture of the temple. However, enjoy some more
photos.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/KknscQQ.BZVH11kr_1m7FeQ.webp&quot; alt=&quot;A Ganesha statue&quot; title=&quot;A Ganesha statue&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/jb3McxQ.GUm6vkQA_Z1nnrF1.webp&quot; alt=&quot;Carvings on walls&quot; title=&quot;Carvings on walls&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;4032&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/WQGjwur.0UbeAkAu_BNCiX.webp&quot; alt=&quot;Temple&quot; title=&quot;Temple&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4032&quot; height=&quot;3024&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/jUYDuQd.Ceev-IRp_Z2soh3h.webp&quot; alt=&quot;Another temple&quot; title=&quot;Another temple&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4032&quot; height=&quot;3024&quot;&gt;&lt;/p&gt;
&lt;p&gt;After this temple, we continued our journey to Chikmagalur. We had booked a
homestay option. The name of the homestay was Sunshine Palm Retreat, if I recall
correctly. It was one of the best stays I have experienced on any trip till now.
It was not crowded, the staff was co-operative, and the ambiance was excellent.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/JUTwVEN.D6qkN6GV_1Mq490.webp&quot; alt=&quot;The Silver Palm Retreat Homestay&quot; title=&quot;The Silver Palm Retreat Homestay&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4032&quot; height=&quot;3024&quot;&gt;&lt;/p&gt;
&lt;p&gt;On the evening of Saturday, we decided to go for our second destination of the
day - the so-called &lt;em&gt;shooting point&lt;/em&gt;. When we searched on Google maps, we found
one location with a similar name. We started driving in that direction. However,
it turned out that we were going to the wrong place. We tried asking locals, but
language was an issue. Most of the signboards are also in Kannada only. Somehow
we ended up getting on the right track and reached the correct location on time.
After reaching there, Google Maps shows that the place is called Bagmane Sunrise
Point. Even this name does not seem to be right.&lt;/p&gt;
&lt;p&gt;As soon we reached there, I realized that all the efforts that we put in
reaching there were worthwhile. It was an open ground area on top of a small
hill at one end of a small village. I started roaming here and there, enjoying
the serenity of nature. I am not a very photogenic person, so I prefer to click
pictures of objects and nature more than standing in front of a camera at
different angles.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/c84g6tX.DFcITEur_pwM4d.webp&quot; alt=&quot;A view at shooting point&quot; title=&quot;A view at shooting point&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4032&quot; height=&quot;3024&quot;&gt;&lt;/p&gt;
&lt;p&gt;We spent around 1.5 hours there and then came back.
&lt;a href=&quot;https://www.cricbuzz.com/live-cricket-scorecard/20264/ind-vs-afg-match-28-icc-cricket-world-cup-2019&quot;&gt;India vs. Afghanistan&lt;/a&gt;
cricket match was live on TV, and we fixed ourselves in front of the TV for the
next 4 hours. India somehow won that match. Thank God!&lt;/p&gt;
&lt;p&gt;The next day, it was raining from the early morning. We did not want to take any
risk by driving on the steep and narrow zig-zag roads. So we dropped our plan to
go to Butter Milk Waterfalls and instead decided to go to Mullayanagiri peaks as
our last destination. We again lost our way, but somehow managed to reach the
place.&lt;/p&gt;
&lt;p&gt;It was drizzling there. However, we were at such a high altitude that we had to
bring our sweaters out. Surprisingly, I found vendors selling Maggi there. I was
not expecting the taste to be good, but I was wrong. For that sort of place, the
Maggi was delicious.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=F9SpC8nFF0A&quot;&gt;https://www.youtube.com/watch?v=F9SpC8nFF0A&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Despite the weather conditions, we decided to climb to the top of the hill. As
we were going up, the weather was turning more and bleaker. Out of five of us,
only three managed to reach the top, including me. The view from the top of the
hill was just amazing. Wherever I saw, I saw just the mountain mist. My clothes
were wet, and my spectacles were completely covered in fog.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/WSP3EE6.IzshUGee_Z1pdgaw.webp&quot; alt=&quot;An inscription&quot; title=&quot;An inscription&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4032&quot; height=&quot;3024&quot;&gt;&lt;/p&gt;
&lt;p&gt;I shot a video when we were coming down from the hilltop.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=So_UD2tpRic&quot;&gt;https://www.youtube.com/watch?v=So_UD2tpRic&lt;/a&gt;&lt;/p&gt;
&lt;br&gt;
&lt;hr&gt;
&lt;p&gt;To summarise, the timing of this trip was not appropriate, but I do not regret
it. I have gone to other hill stations after the monsoons get over, but it is a
different experience altogether to go in a rainy season. Chikmagalur is worth
more than one visit. Do try to go at an appropriate time if you want to visit
more places.&lt;/p&gt;
&lt;p&gt;Thanks for reading. Cheers 😄&lt;/p&gt;</content:encoded></item><item><title>Go + gRPC + OPA - A Perfect Union - Part 3</title><link>https://yashagarwal.in/notes/go-grpc-opa-a-perfect-union-part-3/</link><guid isPermaLink="true">https://yashagarwal.in/notes/go-grpc-opa-a-perfect-union-part-3/</guid><description>Conclude the Go, gRPC, and OPA series by implementing fine-grained authorization using OPA&apos;s Rego policies for a library service.</description><pubDate>Mon, 18 Feb 2019 01:17:15 GMT</pubDate><content:encoded>&lt;p&gt;I finished my last &lt;a href=&quot;https://yashagarwal.in/notes/go-grpc-opa-a-perfect-union-part-2/&quot;&gt;post&lt;/a&gt; with the
following issue -&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Now, here one problem arises, how to make sure that the search results will
not return any book which the user is not authorized to access. We will solve
this problem using OPA in the next and last post of this series.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let&apos;s solve this issue now. We will use OPA&apos;s declarative language, Rego, to
implement policies which will decide on the basis of some user-provided data,
which all objects are to be returned to the user.&lt;/p&gt;
&lt;p&gt;We will also define a list of all the users who are part of this library. Here
we are hardcoding this data, as I did not want to waste my time in implementing
a user registration service, but this functionality is not very important from
our point of view. We will require only one field from this users data - the
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;user_type&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; field. This field will determine what the access level for the user
is. We have already added the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;access_level&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; field in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Book&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; definition of
our proto file.&lt;/p&gt;
&lt;p&gt;When the user wants to search for a particular book, it will provide its
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;user_type&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; the ISBN of the book to our service. Our service will take that ISBN
and pass it to the OPA server. OPA server already has the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Book&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; data and the
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;User&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; data. Now it has the required ISBN to query the Book data. The Rego
policy will query the Book data by ISBN. It will also check for the
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;access_level&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; condition. Moreover, after this operation, it will return the
resultant set of books that satisfy both the requirements.&lt;/p&gt;
&lt;p&gt;Here is the Rego policy -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;go&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;go&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;package&lt;/span&gt; library
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; data.books
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; data.users
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; input
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;search_books[book] {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  input.book.isbn&lt;/span&gt;:= books[i].isbn
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  input.user.user_type &lt;/span&gt;&gt;= books[i].access_level
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  book: books[i]&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;list_all_books[books[i]] {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  input.user.user_type &lt;/span&gt;&gt;= books[i].access_level
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The user data is
&lt;a href=&quot;https://github.com/yashhere/go-library-service/blob/master/OPA/users.json&quot;&gt;here&lt;/a&gt;
and the book data is
&lt;a href=&quot;https://github.com/yashhere/go-library-service/blob/master/add_books.sh&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A sample &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;input&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; request is shown below -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;json&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;json&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;{&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;input&quot;&lt;/span&gt;: {
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;book&quot;&lt;/span&gt;: {
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;      &quot;isbn&quot;&lt;/span&gt;: &quot;1128959038&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;    &quot;user&quot;&lt;/span&gt;: {
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;      &quot;user_type&quot;&lt;/span&gt;: 3
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;input&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is the data that the user is providing. In &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;search_books&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; function,
the input ISBN is matched with the ISBN of all books one by one. Then the
resultant set of books is filtered by &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;user_type&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;access_level&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; (these two
fields are essentially the same). In the last, the resultant set of books is
assigned to the variable &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;book&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; which will be returned to the gRPC service.&lt;/p&gt;
&lt;p&gt;The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;list_all_books&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; function is implemented similarly. The only difference is
that we do not need to filter the books by ISBN. Filtering by &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;access_level&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is
enough.&lt;/p&gt;
&lt;p&gt;Now our library service is completed. It is a very basic service. The intention
was to show that the decision-making process can be offloaded to the OPA to
reduce the complexity of the services. In this example, the advantages might not
be obvious, but in large production environments, where many services are
running, it can make a significant difference.&lt;/p&gt;
&lt;p&gt;The code for this series can be found on my
&lt;a href=&quot;https://github.com/yashhere/go-library-service&quot;&gt;Github&lt;/a&gt; account.&lt;/p&gt;
&lt;p&gt;I hope you liked the article. Share your views and suggestions in the comments.&lt;/p&gt;
&lt;p&gt;Thanks for reading. Cheers :)&lt;/p&gt;</content:encoded></item><item><title>Go + gRPC + OPA - A Perfect Union - Part 2</title><link>https://yashagarwal.in/notes/go-grpc-opa-a-perfect-union-part-2/</link><guid isPermaLink="true">https://yashagarwal.in/notes/go-grpc-opa-a-perfect-union-part-2/</guid><description>Continue building a Go gRPC service with OPA, focusing on protobuf definitions and integrating a REST interface using gRPC-Gateway.</description><pubDate>Sun, 17 Feb 2019 09:14:56 GMT</pubDate><content:encoded>&lt;p&gt;In the last &lt;a href=&quot;https://yashagarwal.in/notes/go-grpc-opa-a-perfect-union-part-1/&quot;&gt;post&lt;/a&gt;, we discussed
about the structure of our library application. In this post, we will define the
data definitions using protobuf, and then we will use these definitions to
create a Go service. We will also add a REST interface to the service. So let&apos;s
get started.&lt;/p&gt;
&lt;h1 id=&quot;defining-proto-definitions&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#defining-proto-definitions&quot;&gt;Defining Proto Definitions&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;gRPC uses protocol buffers for serializing structured data. To define the
structure of the data that you want to serialize, we use a &lt;em&gt;proto&lt;/em&gt; file - it is
a simple text file that contains all the logical pieces of your data in the form
of &lt;em&gt;messages&lt;/em&gt;, and the methods that will be called over the network. To know
more about the syntax of proto files, visit &lt;a href=&quot;https://grpc.io/docs/guides/&quot;&gt;this&lt;/a&gt;
link.&lt;/p&gt;
&lt;p&gt;I have defined the following proto file -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;go&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;go&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;syntax: &lt;/span&gt;&quot;proto3&quot;;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;package&lt;/span&gt; library;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; &quot;google/api/annotations.proto&quot;;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;service LibraryService {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  rpc &lt;/span&gt;ListAllBooks(QueryFormat) returns (Books) {
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    option (google.api.http): {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      post : &lt;/span&gt;&quot;/listBooks&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      body : &lt;/span&gt;&quot;*&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    };&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  };&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  rpc &lt;/span&gt;AddBook(QueryFormat) returns (Response) {
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    option (google.api.http): {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      post : &lt;/span&gt;&quot;/addBook&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      body : &lt;/span&gt;&quot;*&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    };&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  };&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  rpc &lt;/span&gt;SearchBook(QueryFormat) returns (Response) {
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    option (google.api.http): {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      post : &lt;/span&gt;&quot;/searchBook&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      body : &lt;/span&gt;&quot;*&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    };&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  };&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;// the library&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;message Library { Books books: &lt;/span&gt;1; }
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;message Books { repeated Book books: &lt;/span&gt;1; }
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;// metadata about a book&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;message Book {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  string&lt;/span&gt; title: 1;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  string&lt;/span&gt; author: 2;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  string&lt;/span&gt; isbn: 3;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  int32&lt;/span&gt; no_of_copies: 5;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  int32&lt;/span&gt; access_level: 6;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;// details about a user&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;message User {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  enum UserType {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    // https://github.com/golang/protobuf/issues/258&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    GARBAGE: &lt;/span&gt;0;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    Student: &lt;/span&gt;1;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    Administration: &lt;/span&gt;2;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    Faculty: &lt;/span&gt;3;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  }&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  string&lt;/span&gt; name: 1;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  int32&lt;/span&gt; id_no: 2;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  UserType user_type: &lt;/span&gt;4;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;message QueryFormat {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  Book book: &lt;/span&gt;1;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  User user: &lt;/span&gt;2;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;message Response {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  string&lt;/span&gt; action: 1;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  int32&lt;/span&gt; status: 2;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  string&lt;/span&gt; message: 3;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  oneof value {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    Book book: &lt;/span&gt;4;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    User user_data: &lt;/span&gt;5;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;message Empty {}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;To compile it, run the following commands -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;protoc&lt;/span&gt; -I/usr/local/include -I. \
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;-I$GOPATH/src &lt;/span&gt;\
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;-I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis &lt;/span&gt;\
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;--go_out=plugins=grpc:. &lt;/span&gt;\
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;api/library.proto&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;protoc&lt;/span&gt; -I/usr/local/include -I. \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;  -I&lt;/span&gt;$GOPATH/src \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;  -I&lt;/span&gt;$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;  --grpc-gateway_out=logtostderr=true:.&lt;/span&gt; \
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;  api/library.proto&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;It will generate corresponding Golang definitions of the messages and services
defined in the Proto file. These definitions can be used by the server and
client stubs to communicate with each other.&lt;/p&gt;
&lt;h1 id=&quot;implementation-of-go-service&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#implementation-of-go-service&quot;&gt;Implementation of Go service&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Now we can start implementing the code for our services &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;AddBook()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;,
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;ListAllBooks()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;SearchBook()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. It is going to be a very naive
implementation of a library system, but it will be sufficient to learn all the
concepts.&lt;/p&gt;
&lt;p&gt;My implementation of the server stub is hosted
&lt;a href=&quot;https://github.com/yashhere/go-library-service/blob/master/pkg/librarylib/server.go&quot;&gt;here&lt;/a&gt;.
A basic flow diagram of this implementation will look like this -&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/OPA_Service_Flow_Diagram.DYoCMjkv_ZkoFIp.webp&quot; alt=&quot;Architecture&quot; title=&quot;Architecture&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1280&quot; height=&quot;576&quot;&gt;&lt;/p&gt;
&lt;p&gt;The gRPC server will listen on port &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;:50051&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, and a REST HTTP server will listen
on port &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;:8181&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. The OPA server is running on port &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;:8182&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. The REST server is
implemented using
&lt;a href=&quot;https://github.com/grpc-ecosystem/grpc-gateway&quot;&gt;gRPC-Gateway&lt;/a&gt;. There are three
methods - &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;AddBook()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;ListAllBooks()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;SearchBook()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. These methods can
be called using either gRPC methods or using the REST endpoints &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/addBook&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;,
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/listBooks&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/searchBook&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. By design, the library gRPC service will not
implement the authentication part of the service. The main purpose of using gRPC
here is to provide a scalable and secure medium where all the communication
between client and server is happening in binary format, which is slightly more
secure than the traditional mediums. In the current form, this gRPC server will
accept requests from everyone and execute the desired functions. That is not
desirable. What if a student tries to add a book to the library. Only Admins
should be allowed to execute such functions. What if someone who is not a
student of the University tries to access the service. How to stop them?&lt;/p&gt;
&lt;p&gt;There are two steps to solve this issue -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Authentication&lt;/strong&gt; - It mainly deals with the question - who are you? It is a
way to gain access to the system by verifying your identity. In our case, a
user will provide its username and password to access the library service.
Without this authentication, the user will not be able to access the system.
We will not be implementing authentication functionality in our application.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Authorization&lt;/strong&gt; - It deals with the question - which resources are you
allowed to use? OPA can be used here to define various rights based on the
access levels of the users.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you have noticed, I have defined an &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;access_level&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; field in the proto
definition of the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Book&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. This field will tell us what is the minimum access
level required for a user to access this book.&lt;/p&gt;
&lt;p&gt;Again, in the proto definition of the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;User&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, I have defined a &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;user_type&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;
field. This field will serve as an indicator of the access rights of the user.
In the real world, these access rights will be decided after the user has
authenticated herself to the system, but here, we will hardcode the access
rights.&lt;/p&gt;
&lt;p&gt;So, only users with access rights equal to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Administration&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; will be allowed to
add books to the system. Here we do not care who the user is. If the user is
supplying the correct access right, she will be allowed to operate. The
authentication logic in real-world scenarios will determine the &lt;em&gt;who&lt;/em&gt; part.&lt;/p&gt;
&lt;p&gt;There are some books in the library, which have access rights equal to that of a
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Faculty&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. It means that only faculties will be allowed to access those books.
The students will not be able to access these books, even while searching for
books using ISBN. This kind of mechanism can be implemented using OPA very
quickly. We will see the implementation of the OPA part in the next post.&lt;/p&gt;
&lt;p&gt;While querying the service, users are required to supply their identity (at
least &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;user_type&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;) and the book ISBN if they are searching for some book. The
administrators are supposed to provide the name, author, access level, number of
copies, and ISBN while adding the books. I have not added the error checking
functionality in the code, but it should be easy enough to implement such
functionality.&lt;/p&gt;
&lt;p&gt;The
&lt;a href=&quot;https://github.com/yashhere/go-library-service/blob/master/cmd/main.go&quot;&gt;main.go&lt;/a&gt;
file is the starting point of this service. It will spawn two servers in two Go
Routines. Ideally, some synchronization mechanisms should be implemented in the
code to avoid race conditions in some cases - for example, what will happen if
two or more clients are trying to add the same book simultaneously. Here in our
case, nothing serious will happen, as OPA will take only one book per ISBN, and
discard all the other books with the same ISBN even if the other metadata is
different (I designed the service in this way to keep the code easy enough to
understand), but if there are other operations like DeleteBook and IssueBook,
then the race conditions can cause issues.&lt;/p&gt;
&lt;p&gt;In the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;AddBook()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; function, the user provided book details will be sent to the
OPA server using a REST call. OPA will store this information in its in-memory
store at a unique place determined by the ISBN of the book. In actual cases, the
data should be stored in some persistent storage, such as a DB. OPA will take
the information from the DB. Again, to keep the implementation easy enough to
understand, we are not using any such persistent storage. If any other book with
different metadata but the same ISBN comes, then OPA will overwrite the existing
book with the new one.&lt;/p&gt;
&lt;p&gt;In the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;SearchBook()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; function, the user will provide the ISBN of the desired
book. The gRPC service will call the OPA using REST API and find if any such
book exists or not.&lt;/p&gt;
&lt;p&gt;The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;ListAllBooks()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is different in the way that it does not need any ISBN.&lt;/p&gt;
&lt;p&gt;Now, here one problem arises, how to make sure that the search results will not
return any book which the user is not authorized to access. We will solve this
problem using OPA in the next and last post of this series.&lt;/p&gt;
&lt;p&gt;I hope that this post was helpful. If you have any doubts or want to say
anything else, please comment. It will be a great motivation and appreciation
for me.&lt;/p&gt;
&lt;p&gt;Thanks for reading. Cheers 😄&lt;/p&gt;</content:encoded></item><item><title>Go + gRPC + OPA - A Perfect Union - Part 1</title><link>https://yashagarwal.in/notes/go-grpc-opa-a-perfect-union-part-1/</link><guid isPermaLink="true">https://yashagarwal.in/notes/go-grpc-opa-a-perfect-union-part-1/</guid><description>Introduce gRPC and Open Policy Agent (OPA) and outline building a Go-based library service with both gRPC and REST interfaces.</description><pubDate>Sun, 10 Feb 2019 08:59:08 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; – In a series of blog posts, I will be implementing a simple library
application supporting both gRPC and REST interfaces using Go, gRPC, and OPA. My
approach might not be the most optimal one, but I am learning these technologies
currently. Please give your valuable suggestions and be kind :)&lt;/p&gt;
&lt;p&gt;I have been learning the basics of microservices and Golang lately. On the work
front, I got a chance to work on Go, gRPC, and Open Policy Agent as my first
professional project. In this post, I will be demonstrating what I learned in
the last few months. We will be implementing a simple gRPC based library
service, which will be able to serve requests using both gRPC and REST calls. It
will also incorporate the Open Policy Agent (OPA) to provide the authorization
to users. Let&apos;s begin with a quick introduction to gRPC and OPA.&lt;/p&gt;
&lt;h1 id=&quot;grpc&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#grpc&quot;&gt;gRPC&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;gRPC is Google&apos;s implementation for Remote Procedure Calls(RPC). RPC is mainly
used in building scalable distributed systems. While REST has a limited set of
verbs, RPC can define any function calls, including synchronous and asynchronous
calls.&lt;/p&gt;
&lt;p&gt;In gRPC, the client can make procedure calls as if the requests are made to some
local function. However, the underlying client stub (auto-generated) will send
the call to the server. The server will have a similar server stub, which will
be able to handle the requests coming from the client. The server will send the
response to the client using similar mechanisms over the network. All the
communication is serialized to binary format, so it is ideal for distributed
systems as binary format tends to be on the faster side for large amounts of
data.&lt;/p&gt;
&lt;p&gt;For more info about gRPC, visit the official &lt;a href=&quot;https://grpc.io/&quot;&gt;website&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;open-policy-agent-opa&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#open-policy-agent-opa&quot;&gt;Open Policy Agent (OPA)&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;OPA gives us the ability to define a fine-grained policy control mechanism.
However, I think the most critical benefit of using OPA is that it gives you the
ability to decouple your services and the definition of policies from the
enforcement of it.&lt;/p&gt;
&lt;p&gt;There are mainly two parts of OPA -&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A JSON document store where you can define anything from your users, access
roles, permission levels, etc.&lt;/li&gt;
&lt;li&gt;A policy is written in a declarative language. This policy gives you new
derivative data from the original JSON document store evaluated by the
policy. The declarative language is called Rego, and these policies are also
documents that generate results according to the defined policy. The users
query these results.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This info will be sufficient for our use case. More info about it can be found
at the official &lt;a href=&quot;https://www.openpolicyagent.org/&quot;&gt;website&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;the-skeleton-of-our-application&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-skeleton-of-our-application&quot;&gt;The skeleton of our Application&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We will be building a command-line library application. This application will
support adding, deleting, searching, issuing, and returning of books. There are
three types of users – student, faculties, and staff. Not all users have a
similar kind of access level. There are some books which are only reserved for
students, and some are exclusively reserved for faculties and so on.&lt;/p&gt;
&lt;p&gt;I think emulating the
&lt;a href=&quot;https://harrypotter.fandom.com/wiki/Hogwarts_Library&quot;&gt;library&lt;/a&gt; at Hogwarts will
be a good idea here. Students and ordinary people were not allowed inside the
restricted section of the library. We will emulate that restricted section using
the authorization mechanisms provided by OPA.&lt;/p&gt;
&lt;p&gt;The gRPC protocol will handle the communications part in our app, but not
everyone in Hogwarts is using gRPC. Wizards are still in love with REST (not a
bad thing, though), so we will provide them alike the REST interface to interact
with our service. We do not want to face the wrath of the wizards, after all.&lt;/p&gt;
&lt;p&gt;OPA can either be used as a standalone application or be embedded in the Go
service as well. Both approaches have their pros and cons. I have decided to use
OPA as an independent service, as it will be more comfortable that way for us to
push authorization data and policies to it if such a need arises in the future.&lt;/p&gt;
&lt;p&gt;One more issue remains - where to store the added books. Shall we persist them?
In practical scenarios, persistence is always a good idea, but here I do not
want to complicate things too much. We could use any Object storage servers
(e.g., Minio) to store the JSON data generated from our gRPC methods, but that
will unnecessarily add complexity to our simple scenario. Wizards do not like
complicate stuff, you know!&lt;/p&gt;
&lt;p&gt;In the next posts, we will define our gRPC proto file and build the Go service
around it. Then we will add a REST interface to our service for simple CRUD
operations in our application. Then we will add OPA authorization to restrict
our users from adding and viewing books which they are not supposed to access.&lt;/p&gt;
&lt;p&gt;Thank you for reading. Cheers 😄&lt;/p&gt;</content:encoded></item><item><title>2018 - Year in Review</title><link>https://yashagarwal.in/notes/2018-year-in-review/</link><guid isPermaLink="true">https://yashagarwal.in/notes/2018-year-in-review/</guid><description>A personal reflection on 2018, detailing lifestyle improvements, blogging achievements, and a newfound passion for reading and economics.</description><pubDate>Mon, 31 Dec 2018 16:32:08 GMT</pubDate><content:encoded>&lt;p&gt;The year 2018 has been quite a roller coaster year for me. I saw many ups and
downs, many successes, and many failures faced many challenges on the personal
front and struggled to keep myself on track. I have been working hard on
improving my lifestyle (not materialistically) for the last few years, and the
benefits have begun to show up now. This year was a pinnacle in that aspect. A
lot of micro changes happened in my life this year.&lt;/p&gt;
&lt;p&gt;I often read my blog posts from last year. Reading these posts give me a good
feeling about the improvements that I could bring in myself during the previous
three years. Writing year &lt;a href=&quot;https://yashagarwal.in/notes/2017-the-best-till-now/&quot;&gt;reviews&lt;/a&gt; and posts
like &lt;a href=&quot;https://yashagarwal.in/notes/beginning-a-new-journey/&quot;&gt;this&lt;/a&gt;,
&lt;a href=&quot;https://yashagarwal.in/notes/mistakes-that-i-made-in-nitc/&quot;&gt;this&lt;/a&gt; and
&lt;a href=&quot;https://yashagarwal.in/notes/deactivated-my-facebook-account/&quot;&gt;this&lt;/a&gt; serve as documents of my deeds from
past for my future. It helps me in not repeating the same mistakes. As a human
being, I cannot run away from committing mistakes, but I can always make sure
that I do not repeat the same mistakes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Those who cannot remember the past are condemned to repeat it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&quot;blogging--writing&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#blogging--writing&quot;&gt;Blogging &amp;#x26; Writing&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I had set a target to write 15 blog articles at the beginning of this year. In
the end, I managed to achieve this goal. I managed to write 17 blog posts and
six book reviews. My blog managed to get much traffic this year, mainly thanks
to some of my technical posts.&lt;/p&gt;
&lt;p&gt;I got some good responses from people about my technical blog posts. My aim to
start writing technical posts was to keep an account of what I learn. It feels
very nice when I go back to my posts to read how I did something last time. So I
consider myself successful that at least I could benefit from my writing.&lt;/p&gt;
&lt;p&gt;Though, in 2018, after leaving college, the frequency of technical posts on this
blog has dipped to almost zero. It is probably because I am not exploring enough
after joining the corporate world. In college, I used Linux all the time, but
now it is nearly four months since I last booted Linux in my system. I think it
is yet another phase of my learning, and I will take some time adjusting with
this. I have some &lt;em&gt;lovely&lt;/em&gt; technical post ideas, and I hope that I will be able
to articulate them soon next year.&lt;/p&gt;
&lt;h1 id=&quot;reading&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#reading&quot;&gt;Reading&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;For most of the year, I did not pay any heed to books, and I was never very
interested in buying books. However, at the end of October, I purchased a Kindle
Paperwhite. I consider this to be the
&lt;a href=&quot;https://twitter.com/yash__here/status/1075396841267752963&quot;&gt;best&lt;/a&gt; investment
done by me this year. Since buying it, I have read eight books. I finally
managed to finish my
&lt;a href=&quot;https://www.goodreads.com/user_challenges/10979019&quot;&gt;Goodreads reading challenge&lt;/a&gt;
of 10 books. Although I could not finish one book and included one
&lt;a href=&quot;https://www.goodreads.com/book/show/31284204-the-millionaire-booklet&quot;&gt;audiobook&lt;/a&gt;
to this challenge to complete my target on time.&lt;/p&gt;
&lt;p&gt;This year, I discovered my interest in Economics. I am reading some
economics-related literature lately. It is a subtle shift from my all-CS life. I
plan to read a lot of economics-related books in 2019 to gain more expertise in
this domain. But I still need to figure out a way to stop it from interfering
with my first (or second, maybe!) love.&lt;/p&gt;
&lt;p&gt;Some of my favorite reads from this year (not in any particular order) -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Technology / CS&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://danluu.com/branch-prediction/&quot;&gt;Branch Prediction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://research.google/pubs/pub334/&quot;&gt;The Anatomy of a Large-Scale Hypertextual Web Search Engine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://chrisdown.name/2018/01/02/in-defence-of-swap.html&quot;&gt;In defence of swap: common misconceptions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jvns.ca/blog/2018/03/05/things-ive-learned-networking/&quot;&gt;A few things I&apos;ve learned about computer networking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.cloudflare.com/using-go-as-a-scripting-language-in-linux/&quot;&gt;Using Go as a scripting language in Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://rcoh.me/posts/cache-oblivious-datastructures/&quot;&gt;Maximize Cache Performance with this One Weird Trick: An Introduction to Cache-Oblivious Data Structures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cl.cam.ac.uk/~mgk25/mswish/ut-rtc.html&quot;&gt;IBM PC Real Time Clock should run in UT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://c-faq.com/decl/spiral.anderson.html&quot;&gt;The “Clockwise/Spiral Rule”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nvie.com/posts/a-successful-git-branching-model/&quot;&gt;A successful Git branching model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://mattjolson.github.io/2017/12/07/benefits-of-a-classical-education.html&quot;&gt;So, should you do a CS degree?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://beza1e1.tuxen.de/articles/accidentally_turing_complete.html&quot;&gt;Accidentally Turing-Complete&lt;/a&gt;

&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.xda-developers.com/apple-new-iphone-xr-influence-android-trends/&quot;&gt;How Apple&apos;s New Lineup and iPhone XR will Influence Android Trends, for Better and Worse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scotthelme.co.uk/perfect-forward-secrecy/&quot;&gt;Perfect Forward Secrecy - An Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dropbox.tech/security/zxcvbn-realistic-password-strength-estimation&quot;&gt;zxcvbn: realistic password strength estimation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://askubuntu.com/questions/638382/how-can-i-turn-photos-of-paper-documents-into-a-scanned-document&quot;&gt;How can I turn photos of paper documents into a scanned document?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/swlh/chatbots-were-the-next-big-thing-what-happened-5fc49dd6fa61&quot;&gt;Chatbots were the next big thing: what happened?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arstechnica.com/gadgets/2018/07/the-ai-revolution-has-spawned-a-new-chips-arms-race/&quot;&gt;The AI revolution has spawned a new chips arms race&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.theverge.com/2018/6/13/17446660/mozilla-firefox-pocket-recommendations-ceo-nate-weiner-interview-converge-podcast&quot;&gt;How Firefox is using Pocket to try to build a better news feed than Facebook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.diamandis.com/blog/countdown-to-the-singularity&quot;&gt;Countdown to the Singularity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://qz.com/1366350/what-the-hell-is-going-on-with-apple/&quot;&gt;What the hell is going on with Apple?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://interestingengineering.com/why-chinese-artificial-intelligence-will-run-the-world&quot;&gt;Why Chinese Artificial Intelligence Will Run The World&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.technologyreview.com/2018/10/22/139629/europes-quest-for-an-unhackable-quantum-internet/&quot;&gt;Inside Europe&apos;s quest to build an unhackable quantum internet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spectrum.ieee.org/computing/hardware/the-case-against-quantum-computing&quot;&gt;The Case Against Quantum Computing&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Economics&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.wired.com/story/why-hard-escape-amazons-long-reach/&quot;&gt;Why It&apos;s Hard to Escape Amazon&apos;s Long Reach&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.aboveavalon.com/notes/2018/7/11/the-race-to-a-trillion&quot;&gt;The Race to a Trillion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bloombergquint.com/opinion/ambani-is-ready-for-his-triple-play-close-up&quot;&gt;Ambani Is Ready for His Triple Play Close-Up&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.livemint.com/Opinion/M0oJYwIP1OxJWnzaz6Eo8H/Penalty-kicks-and-behavioural-economics.html&quot;&gt;Penalty kicks and behavioural economics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.collaborativefund.com/blog/the-psychology-of-money/&quot;&gt;The Psychology of Money&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bloomberg.com/features/2018-apple-trillion-dollar-world/&quot;&gt;Apple&apos;s Trillion-Dollar World&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hbr.org/2018/08/how-to-beat-mid-career-malaise&quot;&gt;How to Beat Mid-Career Malaise&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.theguardian.com/news/2018/jul/10/the-staggering-rise-of-indias-super-rich&quot;&gt;The staggering rise of India&apos;s super-rich&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.theatlantic.com/business/archive/2018/08/the-problem-with-bezos-billions/566552/&quot;&gt;Jeff Bezos&apos;s $150 Billion Fortune Is a Policy Failure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.washingtonpost.com/business/2018/08/06/how-year-old-roads-predict-modern-day-prosperity&quot;&gt;How 2,000-year-old roads predict modern-day prosperity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://25iq.com/2018/08/11/how-subscription-business-models-are-changing-business-and-investing-the-microeconomics-of-subscriptions/&quot;&gt;How Subscription Business Models are Changing Business and Investing (the Microeconomics of Subscriptions)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.getrichslowly.org/income-vs-wealth/&quot;&gt;What it means to be rich: The difference between income and wealth&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://seekingalpha.com/article/4205122-dark-decade-ahead&quot;&gt;The Dark Decade Ahead&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stratechery.com/2018/the-iphone-franchise/&quot;&gt;The iPhone Franchise&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.newyorker.com/magazine/2018/09/17/the-real-cost-of-the-2008-financial-crisis&quot;&gt;The Real Cost of the 2008 Financial Crisis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/naval/status/1002103360646823936?lang=en&quot;&gt;How to Get Rich (without getting lucky)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://zandercutt.com/2018/08/23/the-approval-economy/&quot;&gt;The Approval Economy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.washingtonpost.com/outlook/five-myths/five-myths-about-capitalism/2018/09/27/3f0b72f6-c06f-11e8-90c9-23f963eea204_story.html&quot;&gt;Five myths about capitalism&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.theverge.com/2018/10/23/17970466/amazon-prime-shopping-behavior-streaming-alexa-minimum-wage&quot;&gt;How Amazon&apos;s Retail Revolution Is Changing The Way We Shop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://evonomics.com/wealth-power-productivity-laurie-macfarlane/&quot;&gt;Why Wealth Is Determined More by Power Than Productivity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://justinjackson.ca/costs&quot;&gt;Let&apos;s Talk About Startup Costs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bloomberg.com/news/articles/2018-11-16/how-companies-get-you-to-pay-more-for-the-same-product&quot;&gt;How Companies Get You to Pay More for the Same Product&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.vox.com/the-goods/2018/10/31/18048340/art-market-expensive-ai-painting&quot;&gt;Why is art so expensive?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nytimes.com/2018/12/18/business/bond-market-risks.html&quot;&gt;Stock Markets Are Wild, but Bond Markets Can Be Dangerous&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.livemint.com/Companies/HNZA71LNVNNVXQ1eaIKu6M/British-Raj-siphoned-out-45-trillion-from-India-Utsa-Patna.html&quot;&gt;British Raj siphoned out $45 trillion from India: Utsa Patnaik&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://theweek.com/articles/809324/how-spot-next-recession&quot;&gt;How to spot the next recession&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Misc&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nytimes.com/2018/02/21/technology/personaltech/smart-things-dumb-stuff.html&quot;&gt;In an Era of &apos;Smart&apos; Things, Sometimes Dumb Stuff Is Better&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.theladders.com/career-advice/einstein-aristotle-and-ockham-on-how-real-geniuses-solve-difficult-problems&quot;&gt;Einstein, Aristotle, and Ockham on how real geniuses solve difficult problems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.theglobeandmail.com/technology/your-smartphone-is-making-you-stupid/article37511900/&quot;&gt;Your smartphone📱is making you👈 stupid, antisocial 🙅 and unhealthy 😷. So why can&apos;t you put it down❔⁉️&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Swarajyamag - Indian Nationalism: The Memories Of History - Part I, Part II, Part III&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.ncase.me/take-your-time/&quot;&gt;Take Your Time&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nytimes.com/2016/02/28/magazine/what-google-learned-from-its-quest-to-build-the-perfect-team.html&quot;&gt;What Google Learned From Its Quest to Build the Perfect Team&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.newyorker.com/magazine/2018/12/10/the-friendship-that-made-google-huge&quot;&gt;The Friendship That Made Google Huge&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/pulse/you-what-write-harry-shum/&quot;&gt;You are what you write&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://swarajyamag.com/ideas/being-dk-in-the-age-of-msd&quot;&gt;Being DK In The Age Of MSD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scroll.in/field/868038/post-retirement-rahul-dravid-is-now-getting-the-unconditional-love-he-always-deserved-as-under-19-world-cup-triumph-showed&quot;&gt;The growing legacy of Rahul Sharad Dravid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.theladders.com/career-advice/the-only-real-way-to-acquire-wisdom&quot;&gt;The Only Real Way to Acquire Wisdom&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fortelabs.co/blog/personal-sprints-applying-design-thinking-to-your-life/&quot;&gt;Personal Sprints: Applying Design Thinking to Your Life&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fs.blog/2018/06/succeed-at-work/&quot;&gt;Smarter, Not Harder: How to Succeed at Work&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.quantamagazine.org/real-life-schrodingers-cats-probe-the-boundary-of-the-quantum-world-20180625/&quot;&gt;Real-Life Schrödinger&apos;s Cats Probe the Boundary of the Quantum World&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.economist.com/graphic-detail/2018/06/15/which-traits-predict-graduates-earnings&quot;&gt;Which traits predict graduates&apos; earnings?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://andrewchen.co/power-user-curve/&quot;&gt;The Power User Curve: The best way to understand your most engaged users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.economist.com/the-world-if/2018/07/07/data-workers-of-the-world-unite&quot;&gt;What if people were paid for their data?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.quantamagazine.org/graduate-student-solves-quantum-verification-problem-20181008/&quot;&gt;Graduate Student Solves Quantum Verification Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.spectator.co.uk/article/the-price-of-looking-busy&quot;&gt;It doesn&apos;t matter how hard you work – just how busy you look&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.paulgraham.com/love.html&quot;&gt;How to Do What You Love&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nytimes.com/2018/08/14/style/how-can-i-focus-better.html&quot;&gt;Finding It Hard to Focus? Maybe It&apos;s Not Your Fault&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://avc.com/2018/08/first-mover-disadvantage/&quot;&gt;First Mover Disadvantage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://the-ken.com/story/the-sharechat-phenomenon/&quot;&gt;The ShareChat Phenomenon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scroll.in/article/890631/vinod-mehta-on-atal-behari-vajpayee-and-the-1998-nuclear-tests-how-a-tired-pm-became-a-bold-pm&quot;&gt;Atal Bihari Vajpayee and his Achilles heel: Excerpts from Vinod Mehta&apos;s memoirs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/the-ascent/is-work-life-balance-a-myth-c328377966de&quot;&gt;Work-life balance is an unhealthy myth&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.engadget.com/2018-09-04-who-controls-your-data.html&quot;&gt;Who controls your data?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.newyorker.com/humor/daily-shouts/your-first-ninety-days-in-hell&quot;&gt;Your First Ninety Days in Hell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://qz.com/1422925/the-public-internet-was-almost-a-democracy/&quot;&gt;The internet can&apos;t handle functioning like a democracy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://waitbutwhy.com/2018/04/picking-career.html&quot;&gt;How to Pick a Career (That Actually Fits You)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fs.blog/2018/10/long-game/&quot;&gt;The Surprising Power of The Long Game&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jotform.com/blog/the-world-needs-polymaths/&quot;&gt;Why the world needs deep generalists, not specialists&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://waitbutwhy.com/2014/12/10-types-odd-friendships-youre-probably-part.html&quot;&gt;10 Types of Odd Friendships You&apos;re Probably Part Of&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I used &lt;a href=&quot;https://www.instapaper.com/&quot;&gt;Instapaper&lt;/a&gt; extensively throughout the year
to manage and save the articles that I liked. Although I was never very
consistent in reading those saved articles, it was still a good exercise. I
finished all my pending pile of saved articles by the end of the year. Moreover,
for this post, it became straightforward for me to recollect those links. This
list grew excessively large, but I did not want to lose any of these links
because of some random third-party service shutting down, so I am adding them
here for easy reference in the future.&lt;/p&gt;
&lt;p&gt;Next year onwards, I plan to read one academic paper from my favorite areas of
CS in every two weeks and summarise them to improve my understanding of the
domain (the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/readings&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; section of my blog was initially intended for
this purpose). Moreover, seeing my experience in the last two months, I feel
encouraged to increase my Goodreads reading challenge to 20 books.&lt;/p&gt;
&lt;h1 id=&quot;work&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#work&quot;&gt;Work&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The year 2018 was a pivotal year for me on this front. It was the year when I
had to come out of the comfort zone of my parents&apos; protection. My professional
life began this year, and I started earning MONEY. It feels delightful when you
see the money gets deposited to your bank account every month for the hard(!)
work that you have done for the last one month. But&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;With great power comes great responsibility.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I believe that I have been able to control this feeling of power quite nicely
until now. Probably being an &lt;em&gt;Agarwal&lt;/em&gt; helped :P&lt;/p&gt;
&lt;p&gt;Coming back to work, those who do not know, I joined Cisco Systems this year as
a Software Engineer. The job is pretty good for my initial expectations. I made
some good friends. First time in my life, I managed to make a group of friends.&lt;/p&gt;
&lt;p&gt;Quite an achievement.&lt;/p&gt;
&lt;h1 id=&quot;studies&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#studies&quot;&gt;Studies&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This year was officially my last year in formal education.&lt;/p&gt;

&lt;p&gt;Although I failed to finish my bachelors with a satisfactory final GPA (at least
I am not happy with it), I am very much satisfied with all my learnings from
college. I learned many life lessons, kept myself in check, built some useful
contacts, learned a lot about many CS-related things, and ended up with a decent
job in the end.&lt;/p&gt;
&lt;p&gt;However, I sense that this is not the happy ending of my journey towards
learning, and I have a lot more to learn. I recently read the book &quot;The
Alchemist,&quot; and the central theme of this book is to keep looking for your
legend. I am still searching for my legend. In 2019, I expect to find new ways
to keep learning and explore new areas both in CS and other fields of life.&lt;/p&gt;
&lt;h1 id=&quot;relationships&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#relationships&quot;&gt;Relationships&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Before this year, I had an assumption that I lack social skills. I hesitated in
talking to people. I decided to change it this year. I was waiting for a change
in my life, probably because NITC had become too monotonous for me. It was one
of my new year&apos;s resolution that I will change myself and become more
approachable to people.&lt;/p&gt;
&lt;p&gt;I do not know if I have changed or not, but I feel much more confident now than
ever in communicating with people. I hope I will continue to improve in 2019 as
well.&lt;/p&gt;
&lt;h1 id=&quot;social-media&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#social-media&quot;&gt;Social Media&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I was trying to get rid of Facebook for quite some time. This year, I finally
managed to control my addiction. For a good part of the year, either my Facebook
account remained deactivated, or I was logged out of it. In the past, I used to
feel a strong urge to open Facebook every ten minutes, but this year, I was able
to keep this urge in control. When my account was not deactivated, I kept myself
so busy in other works, that I did not even think of Facebook.&lt;/p&gt;
&lt;p&gt;Moreover, the good thing is that I did not notice any symptoms of withdrawal
symptoms because of this sudden quitting of Facebook. A friend&apos;s advice worked
nicely. It was quite tricky, indeed.&lt;/p&gt;
&lt;p&gt;I was never addicted to any other social media platform, but I decided that I
can use Twitter for my benefit. I feel Twitter is a useful tool if utilized
correctly. I followed many people who tweet regularly about CS related stuff. I
open Twitter once every 2-3 days for a very short duration to collect some
articles and tips. Nowadays, these articles, along with a few blog articles from
Feedly, mainly form my Instapaper feed. Though Instapaper recently switched to
commercial model again, I decided to keep using it for the time being until I
find some other alternative.&lt;/p&gt;
&lt;h1 id=&quot;miscellaneous&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#miscellaneous&quot;&gt;Miscellaneous&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I had decided to exercise for at least 90% part of 2018. I failed miserably.
Leave alone every day; I could not even do it continuously for one month. I need
to make this a top priority. Otherwise, it is going to create trouble for me
soon.&lt;/p&gt;
&lt;p&gt;For the last two years, I am trying to get up early in the morning every day. My
body does not seem to care, though. It seems a classic example of the struggle
between mind and body. My brain says that I am an early bird, but my body
straightforwardly rejects this idea. I have felt the positives of waking up
early, so I am still trying my best so that my body can adjust to this change. I
will keep working on this habit in 2019 as well.&lt;/p&gt;
&lt;p&gt;I noticed a bad habit in myself - procrastination. I procrastinated a lot
in 2018. Things that I could have finished well within the deadlines took me
ages to complete. I was always late in my BTech project deadlines, I could not
finish one of my hobby projects, I could not finish my study targets on time,
and many other such examples haunted me this year. It is one of my most
important goals of 2019 that I need a way to find how to concentrate on one
thing at a time. Many things distract me while I am working. Technology itself
is a significant distraction, but because I am a CS professional, this is one
thing from which I cannot run away. However, I will still try to avoid getting
distracted by my &lt;em&gt;curiosity&lt;/em&gt; and put more focus on doing work.&lt;/p&gt;
&lt;p&gt;I am writing more than ever. However, with my increased writing, my English
vocabulary is not enough anymore. This year, it happened many times that I
wanted to write something, but because of the lack of proper words in my
vocabulary, I had to settle with &lt;em&gt;inferior&lt;/em&gt; words. I tried multiple times this
year to work on improving my vocabulary, but I failed badly. I will increase my
focus on improving my knowledge of English in 2019 so that such small issues do
not stop me from adding something to my skills.&lt;/p&gt;
&lt;p&gt;This year, I experimented and tried to organize myself with to-do lists. It was
a fruitful exercise, and it had a lot of sound effects on my productivity. The
days when I made a to-do list, I felt very energetic and encouraged to finish
all the tasks on my list. However, then I noticed one thing, I could not
continue doing this for more than a few days at once. For initial days, I felt
encouraged to complete my tasks, but soon it began to appear as a burden, and I
felt exhausted. So it seems that something in the middle will work for me. This
year, I will continue using to-do lists (I use Google Keep for this) but for
short durations of time. I will refrain from using it every day to avoid getting
exhausted. I am considering a switch to &lt;a href=&quot;https://www.notion.so/&quot;&gt;Notion&lt;/a&gt; to
maintain my monthly and long-term goals. Probably that will also help me in
keeping track of my goals without feeling the heat.&lt;/p&gt;
&lt;p&gt;All of my friends love to travel. It seems a common habit in most of my friends.
However, I am an exception. I&apos;m not particularly eager to go on trips. I
attribute it to my issues with motion sickness. For the whole year of 2018, I do
not have a single trip memory other than my travels to Bengaluru and Jaipur
airports. Oh yeah, after thinking for some time, I recalled that I went on one
trip from Bengaluru to Calicut to attend my convocation ceremony. That&apos;s all! I
will &lt;em&gt;consider&lt;/em&gt; accepting trip invitations from my friends in 2019. Up until
now, I keep refusing to join them in their trips due to my health issues, my
desire to stay in solitude and partially because of my unwillingness to explore
anything outside technology. However, it is time I start changing myself.&lt;/p&gt;
&lt;p&gt;It was a grave mistake that during my four-year stay in Kerala, I did not try to
learn Malayalam. I feel that I missed an excellent opportunity to learn a new
language. Although I am as bad as other north Indians when it comes to knowing
multiple languages (correct me if I am wrong, I do not intend to generalize all
north Indians), I think that learning a new language can be very beneficial for
&lt;em&gt;some parts of my brain&lt;/em&gt;. Now I am in Karnataka, yet another south Indian state
and with yet another language. It is an excellent opportunity, and I am not
going to repeat my mistake this time. Even if I do not succeed in learning
Kannada, it will provide enough challenges to my brain for the short term. Who
knows, it might also give me a new skill!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Welcome 2019, I hope that you will help me in taking a step closer to
discovering myself. Give me new experiences, keep me grounded and help me in
contributing to the progress of my India.&lt;/strong&gt; 😊&lt;/p&gt;</content:encoded></item><item><title>Beginning a New Journey</title><link>https://yashagarwal.in/notes/beginning-a-new-journey/</link><guid isPermaLink="true">https://yashagarwal.in/notes/beginning-a-new-journey/</guid><description>A personal reflection on career choices, self-introspection, and the journey of personal growth, emphasizing life lessons and breaking comfort zones.</description><pubDate>Sat, 25 Aug 2018 15:46:41 GMT</pubDate><content:encoded>&lt;p&gt;When I was in eighth (or was it ninth?) class, one of our teachers asked in the
class, what do you want to become in your life? People said a lot of things.
When my turn came up, I stood up and said, &lt;em&gt;&quot;Mein software engineer banana
chahta hu&quot;&lt;/em&gt; (I want to become a software engineer). It was not that I was
genuinely interested in Computers. When I look back now, I realize that it was
my cousins who affected my choice (in an indirect way), and their achievements
fascinated me to aim at this particular career choice.&lt;/p&gt;
&lt;p&gt;My whole life for the last seven years was revolving around this one dream(!) of
getting a job in an MNC. I got my chance when I got placed in Cisco last
Monsoon. I was super excited about joining Cisco since then. Perhaps because of
the MacBook on which I am typing this article right now 😄 and partly because of
the monotonicity of the NIT-C environment. I wanted to break out of the comfort
zone that I had built there around myself in NIT-C. Changing place seemed the
only viable option.&lt;/p&gt;
&lt;p&gt;I have been doing a self-introspection for the last four to five months. My blog
posts from the previous few months reflect some hints about my introspections. I
have mentioned my observations here and there in a few of my blog posts. I
discovered some unique aspects of my personality. On the other hand, I found out
some traits which are pretty weird (in my opinion :) ). I am not going to
publish all of my findings, but one thing became apparent, my social anxiety
requires my immediate attention.&lt;/p&gt;
&lt;p&gt;It is quite difficult to change some aspects of our personality; usually those
we are born with. But most of the qualities that define someone keeps changing.
Life experiences play an essential role in determining a person&apos;s character.
Success and failure define a person. I firmly believe that no person ever
remains the same. People continuously go through phases of realizations and the
ups and downs in the career, academics, broken trusts, dampening creativity,
growing age, success, glory, hatred, and betrayals. People become what they are
because of the world around them. These realizations come from experiences and
experiences that come from bad experiences.&lt;/p&gt;
&lt;p&gt;I learned this the hard way!&lt;/p&gt;
&lt;p&gt;So, I decided, I will not commit those similar set of mistakes again. I will
make new mistakes 😜. I realized that there exists a world outside computers and
tech. I need to go and talk to people. If not random strangers, I should talk to
my friends, take part in various activities, play some sport, focus on my
fitness and mental health, and go on trips. And of course, perform well in work
and maintain a good work-life balance if it is not a
&lt;a href=&quot;https://medium.com/the-ascent/is-work-life-balance-a-myth-c328377966de&quot;&gt;myth&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I cannot change the past now. It is only the future that is yet in my power. I
am eager to see how my current actions are going to affect my future.&lt;/p&gt;
&lt;p&gt;At last, let me finish this article by quoting Winston Churchill (Although I am
not a big fan of him, this quote is worth sharing).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If we open a quarrel between past and present, we shall find that we have lost
the future.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Cheers. 😄&lt;/p&gt;</content:encoded></item><item><title>The Good and Bad about CSED of NIT-C</title><link>https://yashagarwal.in/notes/the-good-and-bad-about-csed-of-nit-c/</link><guid isPermaLink="true">https://yashagarwal.in/notes/the-good-and-bad-about-csed-of-nit-c/</guid><description>An honest review of NIT Calicut&apos;s Computer Science department: insights on faculty, academic focus, and vibrant student club activities.</description><pubDate>Thu, 14 Jun 2018 12:29:28 GMT</pubDate><content:encoded>&lt;p&gt;Four years ago, in this very month of June, JEE Mains results were out. I had
screwed up my JEE Advanced, so I had to settle for an NIT. My AIR was good
enough to get me a seat of Computer Science and Engineering in any of the NITs
except the first three (at that time Trichy, Warangal, and Surathkal). I was
skeptical about going to &lt;a href=&quot;http://nitc.ac.in/&quot;&gt;NIT Calicut&lt;/a&gt; because of its
distance from my native place, so NIT Allahabad was the most suitable choice.
However, in the end, I decided to give preference to NIT Calicut over NIT
Allahabad. One of the many reasons for this decision was an excellent
&lt;a href=&quot;https://dsanghi.blogspot.com/2011/05/my-2011-list-of-recommended-csit.html&quot;&gt;article&lt;/a&gt;
by Dr. Dheeraj Sanghi, a retired professor from IIT Kanpur. His blog post was
the primary reason; I decided to go with NIT Calicut. Now that I have graduated
from NIT Calicut, I think it is the right time to document my observations about
the CSE department of NIT Calicut from the perspective of a student.&lt;/p&gt;
&lt;p&gt;My exposure to the CSE department was limited to the facilities provided to
undergraduate students only (almost everything except some academic facilities),
so I am not entirely sure if this article will help any of the postgraduate
students out there. However, some points below might help you decide about the
non-academic activities of the department.&lt;/p&gt;
&lt;h1 id=&quot;faculties&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#faculties&quot;&gt;Faculties&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Like every other NIT, NIT Calicut also suffers from the lack of permanent
faculties. Most of the faculties in the department are recruited on a contract
basis (ad-hoc). It is &lt;strong&gt;not&lt;/strong&gt; necessarily a
&lt;a href=&quot;https://dsanghi.blogspot.com/2018/05/teaching-by-temps-it-is-budget-issue-too.html&quot;&gt;bad&lt;/a&gt;
thing, but many a time, an ad-hoc faculty gets to teach a subject where one does
not hold strong command. In that case, the subject becomes a burden for both
student and teacher. It happened to me many times when I was stuck in a
situation that I ended up losing my interest in the subject as well as grades.&lt;/p&gt;
&lt;p&gt;Most of the core subjects are taught by permanent faculties who are very good at
their subjects. These faculties are very experienced and are alumni of some of
India&apos;s top IITs and IISc. The department used to
&lt;a href=&quot;https://dsanghi.blogspot.com/2011/05/my-2011-list-of-recommended-csit.html&quot;&gt;ask&lt;/a&gt;
new hires to get a postgraduate degree from some IIT or IISc, but this does not
seem to be the case anymore.&lt;/p&gt;
&lt;p&gt;Most of the professors prefer to teach traditional computer science subjects, so
if you are interested in AI, Data Science, or any other such areas of computer
science, then you might have to depend on self-study.&lt;/p&gt;
&lt;h1 id=&quot;club-activities&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#club-activities&quot;&gt;Club Activities&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;http://assoc.cse.nitc.ac.in/&quot;&gt;CSEA&lt;/a&gt; is the main departmental club that
organizes almost every co-curricular activity in the department. In my opinion,
CSEA is the best department association in NIT Calicut. I was not a member of
CSEA, so all of my views are from the perspective of an outsider. CSEA organizes
talks and workshops for the freshers from time to time. I attended all the
lectures and seminars arranged by CSEA in my initial years, and I feel that
those workshops were quite beneficial for me as a student.&lt;/p&gt;
&lt;p&gt;FOSSCell is a group of students who contribute to open-source software. FOSSCell
organizes workshops related to Linux and open source contributions. It also
organizes &lt;a href=&quot;http://fossmeet.in/&quot;&gt;FOSSMeet&lt;/a&gt;, the yearly free and open-source
software conference organized in NIT-C. It is one of the largest gatherings of
open source enthusiasts in South India. I have written two posts about my
experience as a part of the organizing team of FOSSMeet. You can read them
&lt;a href=&quot;https://yashagarwal.in/notes/fossmeet-17/&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://yashagarwal.in/notes/fossmeet-18/&quot;&gt;here&lt;/a&gt;. Attending and
organizing FOSSMeet is one of the best experiences of my college life. The
current executives of FOSSCell are actively working on improving the state of
open source contributions in NIT-C. I hope the situation will change in the
coming years.&lt;/p&gt;
&lt;p&gt;The students manage all the labs in the department. The
&lt;a href=&quot;http://athena.nitc.ac.in/&quot;&gt;Software Systems Lab&lt;/a&gt; is assigned to undergraduate
students. This lab is probably the crown jewel and pride of every CS student of
NIT Calicut. It remains open most of the time. All the department servers are
kept in this lab and are managed independently by the student administrators
chosen by the student administrators. The student administrators are given the
responsibility to maintain all the department websites. I do not know if any
other university or college in India provides such independence to its students.
I was one of the student administrators in this lab, and I consider that this
was the best thing that happened to me during my graduation.&lt;/p&gt;
&lt;h1 id=&quot;the-infrastructure&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-infrastructure&quot;&gt;The Infrastructure&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;A traditional computer science course does not require many types of equipment
except a laptop and a fast enough internet connection. Internet speed is not
extraordinary in NIT-C, but it was sufficient for me. The network administrators
blocked many websites, but if the site is related to coursework, sending a short
mail was enough in most cases to get it unblocked.&lt;/p&gt;
&lt;p&gt;The labs are equipped with modern computer systems, and Ubuntu is installed on
almost every department system. The particular emphasis on the use of
open-source software is a big plus point for the department.&lt;/p&gt;
&lt;h1 id=&quot;courses&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#courses&quot;&gt;Courses&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The curriculum was last updated in 2010. Since then, six batches have graduated.
I think it is an excellent time to consider revising it. The current curriculum
is good enough for most traditional CS subjects, but its focus on the present
buzzwords of the CS world is very less. I heard that the department changed the
curriculum for the batches joining 2017 onwards, but I doubt that there are any
significant changes.&lt;/p&gt;

&lt;p&gt;The academics are taken quite seriously in the department (apparently). The
level of question papers in examinations is generally very tough. I always felt
the heat, at least. However, teachers are quite friendly and will help you with
any of your queries.&lt;/p&gt;
&lt;p&gt;The situation of lab courses (except OS, Compilers, and DSA lab) in the
department is very pathetic. Operating Systems lab and Compiler lab have a
well-defined structure, and the feeling of developing your tiny OS or compiler
is one of the best feelings ever. Data Structure and Algorithms lab runs in
parallel to the corresponding theory course, and that helps students in
understanding theory by practice.&lt;/p&gt;
&lt;p&gt;I cannot say the same about any other lab in the department; most of the
students end up learning nothing new from these lab courses. The problem is in
the way these courses are handled. There does not seem to be a proper structure
of teaching in these courses. Students are expected to learn on their own and
come to the lab and give exams. Although most of the time, the corresponding
theory course carries marks for a mini project which compensates for the lab
course, these lab courses do have some scope for improvements.&lt;/p&gt;
&lt;h1 id=&quot;placements--higher-studies&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#placements--higher-studies&quot;&gt;Placements &amp;#x26; Higher Studies&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The department does not handle placements, but the quality of education and the
focus on industry-oriented courses do affect the placements. The placement
department of NIT-C has been doing an excellent job of maintaining a track
record of over 90% placements from computer science every year.&lt;/p&gt;
&lt;p&gt;Department, as such, does not focus on placements much. I feel that the
department is more interested in making researchers than software engineers.
Most of the courses are very heavily inclined towards theory. From my batch, I
know at least ten people who are planning to go to the USA for higher studies in
the next two years. The faculties also encourage students to pursue higher
education (and subsequently research). Perhaps, it is one of the reasons that
the state of competitive coding is not very good in the department.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Despite continuous lack of good permanent faculties and its location
disadvantages, CSED of NIT-C has managed to produce competent engineers year by
year. Spending four years in Kerala can be a different experience for outsiders,
especially North Indians, but it is an experience worth gaining. If you have a
good rank in JEE Mains and do not mind going too far from home, CSED of NIT
Calicut is an excellent choice. I hope you will not regret the decision, though
I will not say the same about other departments of NIT-C.&lt;/p&gt;
&lt;p&gt;If you decide to join NIT-C, do read my article about my
&lt;a href=&quot;https://yashagarwal.in/notes/mistakes-that-i-made-in-nitc/&quot;&gt;experience&lt;/a&gt; at NIT Calicut.&lt;/p&gt;
&lt;p&gt;Thanks to my friends &lt;a href=&quot;https://www.linkedin.com/in/aashishsatya&quot;&gt;Aashish&lt;/a&gt;,
&lt;a href=&quot;https://www.linkedin.com/in/mahaveer-chouhan-575abba7/&quot;&gt;Mahaveer&lt;/a&gt; and
&lt;a href=&quot;https://www.facebook.com/faris.shajahan.1&quot;&gt;Faris&lt;/a&gt; for reading the drafts of
this article and providing their suggestions.&lt;/p&gt;
&lt;p&gt;Best wishes. Cheers 😄&lt;/p&gt;</content:encoded></item><item><title>Battery Notifications in i3</title><link>https://yashagarwal.in/notes/battery-notifications-in-i3/</link><guid isPermaLink="true">https://yashagarwal.in/notes/battery-notifications-in-i3/</guid><description>Set up custom low battery notifications for i3 window manager on Linux, including bash scripting and handling cron environment variables.</description><pubDate>Tue, 12 Jun 2018 04:15:46 GMT</pubDate><content:encoded>&lt;p&gt;I am using &lt;em&gt;i3&lt;/em&gt; window manager for the last seven months, and it has been a
pleasant and productive experience so far. There were a few hiccups here and
there, but that is expected with such minimalistic setups. One thing that I
never noticed was the lack of notifications on critical battery levels. For the
last few months, my laptop battery was discharging to 0% all the time. Probably
this proved to be too fatal for my battery. According to this
&lt;a href=&quot;https://lifehacker.com/how-often-should-i-charge-my-gadgets-battery-to-prolong-5875162&quot;&gt;article&lt;/a&gt;,
lithium-ion batteries are not expected to go from 100% to 0% frequently. I
recently bought a new battery, and I did not want to reduce the lifespan of this
battery too. So I decided to set up battery notifications for my i3 setup.&lt;/p&gt;
&lt;p&gt;I &lt;a href=&quot;https://angelos.dev/2016/06/low-battery-notification-in-i3wm/&quot;&gt;found&lt;/a&gt; a bash
script which shows a notification using &lt;em&gt;notify-send&lt;/em&gt; when battery charge level
reaches or drops below a configured threshold. However, I had to do some
additional steps to make this script work on my system.&lt;/p&gt;
&lt;p&gt;The first issue was the &lt;em&gt;lockfile&lt;/em&gt; program, which was not installed in my
system. I installed it using the following command.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; apt install procmail&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The second issue was more difficult to solve. I planned to set up the script to
run every minute using &lt;em&gt;cron&lt;/em&gt;. However, it turns out that cron operates in a
very
&lt;a href=&quot;https://askubuntu.com/questions/23009/why-crontab-scripts-are-not-working/23438#23438&quot;&gt;minimalistic&lt;/a&gt;
environment and notify-send requires the presence of some special variables in
the environment. These variables are &lt;strong&gt;DBUS_SESSION_BUS_ADDRESS&lt;/strong&gt;,
&lt;strong&gt;XAUTHORITY&lt;/strong&gt; and &lt;strong&gt;DISPLAY&lt;/strong&gt;. To provide the values of these variables to the
cron environment, I modified the script and sourced a new file &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;.bat_envs&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;.&lt;/span&gt; /home/yash/.bat_envs
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;THRESHOLD&lt;/span&gt;=15
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;lock_path&lt;/span&gt;=&apos;/tmp/battery.lock&apos;
 
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;lockfile&lt;/span&gt; -r 0 $lock_path 2&gt;/dev/null || exit
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;acpi_path&lt;/span&gt;=$(find /sys/class/power_supply/ -name &apos;BAT*&apos; | head -1)
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;charge_now&lt;/span&gt;=$(cat &quot;$acpi_path/charge_now&quot;)
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;charge_full&lt;/span&gt;=$(cat &quot;$acpi_path/charge_full&quot;)
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;charge_status&lt;/span&gt;=$(cat &quot;$acpi_path/status&quot;)
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;charge_percent&lt;/span&gt;=$(printf &apos;%.0f&apos; $(echo &quot;$charge_now / $charge_full * 100&quot;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt; |&lt;/span&gt; bc -l))
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;message&lt;/span&gt;=&quot;Battery running critically low at $charge_percent%!&quot;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;if&lt;/span&gt; [[ $charge_status == &apos;Discharging&apos; ]] &amp;#x26;&amp;#x26; [[ $charge_percent -le $THRE
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;SHOLD ]]; &lt;/span&gt;then
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  /usr/bin/notify-send&lt;/span&gt; -u critical &quot;Low battery&quot; &quot;$message&quot;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  current_date_time&lt;/span&gt;=&quot;`date +%Y%m%d%H%M%S`&quot;;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;  echo&lt;/span&gt; &quot;[BATTERY LOG] = $charge_percent% on $current_date_time&quot;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;fi&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;rm&lt;/span&gt; -f $lock_path&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Read this blog
&lt;a href=&quot;https://angelos.dev/2016/06/low-battery-notification-in-i3wm/&quot;&gt;post&lt;/a&gt; to
understand how this script works.&lt;/p&gt;
&lt;p&gt;As the notify-send requires some special X session environmental variables, we
will need a method to provide these variables to notify-send in cron
environment. The safest way to get X session related environmental variables is
to get them from the environment of a process of the user who is logged on to X.
The following script will run every time a user logs in and stores these
variables in a file &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;.bat_envs&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;

&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;env_path&lt;/span&gt;=&quot;$HOME/.bat_envs&quot;
 
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;rm&lt;/span&gt; -f &quot;${env_path}&quot;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;touch&lt;/span&gt; &quot;${env_path}&quot;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;copy_envs&lt;/span&gt;=&quot;XAUTHORITY DISPLAY DBUS_SESSION_BUS_ADDRESS&quot;
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;for&lt;/span&gt; env_name in $copy_envs
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;do&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;    env&lt;/span&gt; | grep &quot;${env_name}&quot; &gt;&gt; &quot;${env_path}&quot;;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;    echo&lt;/span&gt; &quot;export ${env_name}&quot; &gt;&gt; &quot;${env_path}&quot;;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;done&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;chmod&lt;/span&gt; 600 &quot;${env_path}&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;To run this script at startup, I added this file to the i3 config file with the
following command.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;exec&lt;/span&gt; --no-startup-id &quot;path to your script&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Then at the end of cron file, I added a new entry for the battery monitoring
script.&lt;/p&gt;
&lt;p&gt;To open cron file:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;crontab&lt;/span&gt; -e&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now add the following line to the end of the file and save the file.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;*&lt;/span&gt; * * * * bash &quot;path to your script&quot; &gt;&gt; &quot;path to your log file&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Replace the &lt;em&gt;path to your script&lt;/em&gt; (with double quotes) with your script path and
the &lt;em&gt;path to your log file&lt;/em&gt; with a path where you want to save your log file.&lt;/p&gt;
&lt;p&gt;Now every minute, this script will be executed, and if your battery percent
drops below the threshold value, you will be notified with a notification
bubble.&lt;/p&gt;
&lt;p&gt;I tested this procedure on &lt;em&gt;Ubuntu 18.04 with i3&lt;/em&gt;. It should work on Arch Linux
and other non-Debian distributions also, but the steps might be slightly
different due to various reasons. Please comment if you face any issues with the
setup.&lt;/p&gt;
&lt;p&gt;Thank you for reading the article. Cheers 😄&lt;/p&gt;</content:encoded></item><item><title>Mistakes That I Made in NITC</title><link>https://yashagarwal.in/notes/mistakes-that-i-made-in-nitc/</link><guid isPermaLink="true">https://yashagarwal.in/notes/mistakes-that-i-made-in-nitc/</guid><description>Reflecting on key lessons and mistakes from college life at NITC, covering studies, communication, and personal growth for future self-improvement.</description><pubDate>Fri, 01 Jun 2018 04:51:45 GMT</pubDate><content:encoded>&lt;p&gt;Now that I am graduated from NIT Calicut, one more chapter of my life is over.
It is time to move on to the next page, but before I begin that phase, I thought
it would be nice, to sum up, the experience that I gathered in NIT Calicut. The
last four years have been great for me. I learned a lot of new life lessons, but
there were some decisions that I could have avoided. I take full responsibility
for my actions and do not blame anybody for the same. Although I do not regret
taking any of those decisions, I feel it is crucial to document all those
lessons before they vanish from my &lt;em&gt;otherwise&lt;/em&gt; average memory. This post is
intended to serve as a document for my future self, but most of the content here
should be able to help anyone who happens to read this post. Most of this
content has been taken from my journal, which I maintained (not consistently)
over the last two years.&lt;/p&gt;
&lt;h1 id=&quot;studies&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#studies&quot;&gt;Studies&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;From the first year itself, I had an impression from various online QA sites and
some seniors that studies are not a big deal in college. That was a grave
mistake which cost me a lot during my college life. I tried to compensate for it
in the latter half of my graduation, but that was not enough.&lt;/p&gt;
&lt;p&gt;While my friends used to learn by teaching each other, I never enjoyed studying
in groups. I wish I had participated more in such group learning activities.&lt;/p&gt;
&lt;p&gt;Most of the courses taught in traditional colleges like NITC are useless, in my
opinion. However, Data Structures and Algorithms(DSA) was one subject which
shows its importance again and again. It is one of those subjects where I should
have put more attention. Although I was suffering from a fracture at the time of
this course, some more efforts from my side could have changed things as they
are today.&lt;/p&gt;
&lt;h1 id=&quot;wrong-learning-methods&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#wrong-learning-methods&quot;&gt;Wrong learning methods&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I always tended to learn anything new using the tutorials available on the
Internet. It is fine, but I never tried to do any projects/practicals to
strengthen my learning. In my experience, it is always better to learn any
programming language by doing projects in it.&lt;/p&gt;
&lt;p&gt;My first programming language was C, which was taught in an introductory course
in the first year. C is a relatively low-level language, and it helped me in
understanding many concepts and working on many systems related stuff. Still, I
feel that it is also one of the reasons that I am not able to think in
higher-level abstraction. When I started learning Python, I was not able to
think anything in abstract terms. I wish I had put more effort into learning
Python or any other OOP language early in my college life.&lt;/p&gt;
&lt;h1 id=&quot;communication&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#communication&quot;&gt;Communication&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I have always been an introvert person when it comes to communicating with
people. I wish I had worked on improving this aspect of my personality. For the
first two years, I never asked any seniors for advice, never asked any questions
in the classroom, never discussed project ideas with any faculty. I tried to
improve myself in the last two years, and I feel satisfied with my efforts. In
my opinion, it is always better to ask a more experienced person for their
advice than to take blind steps and regret later.&lt;/p&gt;
&lt;p&gt;I was hesitant about talking to people from different linguistic backgrounds in
my first and second years. Again thanks to my inability to communicate with new
people. I improved this later, but first impressions are crucial, if not
everything.&lt;/p&gt;
&lt;h1 id=&quot;friends-and-seniors&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#friends-and-seniors&quot;&gt;Friends and seniors&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;In my first year, I made a mistake by choosing to befriend some people who
identified themselves as &lt;em&gt;state seniors&lt;/em&gt; (people from the same north Indian
state as I am). I was naive in identifying people at that time, but when I look
back now, I feel that if I had avoided those people and invested that time in
learning something related to CS, I could have gained more out of college. For a
person who was entirely new for CS, that one year&apos;s time was very crucial, and I
completely wasted it. It took me two years to rectify my mistake.&lt;/p&gt;
&lt;h1 id=&quot;not-taking-breaks&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#not-taking-breaks&quot;&gt;Not taking breaks&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I never took breaks from learning new things. I always put my work ahead of my
personal life. That was the wrong approach. However, I do not blame myself for
this. I was new to such work-life equations, and I did not realize the
requirement to maintain a proper work-life balance. I wanted to learn a lot of
new things, and college provided me a suitable environment, but I feel that I
exhausted myself many times. That resulted in my loss of interest from Computer
Science also in the second year.&lt;/p&gt;
&lt;h1 id=&quot;writing-and-reading&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#writing-and-reading&quot;&gt;Writing and Reading&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I was never a voracious reader in my childhood. I never tried to spend my free
time with books. After coming to college, I saw many people reading books day
and night. That inspired me to develop a new hobby of &lt;strong&gt;Reading&lt;/strong&gt;. Although I
still do not read a lot (just 5-6 books a year), it is better than reading none.&lt;/p&gt;
&lt;p&gt;I started this blog in the second year. My intention was &lt;em&gt;not&lt;/em&gt; to write. I just
wanted to learn how to set up Wordpress and Jekyll. However, slowly I developed
the habit of writing. I now consider it the biggest takeaway from college.
Writing a blog has helped me learn new things and systematically explain things.&lt;/p&gt;
&lt;p&gt;I tried to write a journal to document significant events in life, but I could
not maintain it regularly. That is one thing which I would like to improve in
the coming years.&lt;/p&gt;</content:encoded></item><item><title>Proxy Your Requests to the Backend Server With Grunt</title><link>https://yashagarwal.in/notes/proxy-your-requests-to-the-backend-server-with-grunt/</link><guid isPermaLink="true">https://yashagarwal.in/notes/proxy-your-requests-to-the-backend-server-with-grunt/</guid><description>Overcome CORS issues in web development by learning to proxy frontend requests to your backend server using Grunt and grunt-connect-proxy.</description><pubDate>Tue, 15 May 2018 11:44:13 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;This article was originally published on
&lt;a href=&quot;https://www.zeolearn.com/magazine/proxy-your-requests-to-the-backend-server-with-grunt&quot;&gt;zeolearn&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you are working on large projects, it is undoubtedly a good idea to have a
build script or some task scripts to help to automate some of the repetitive
parts of the development process. For JavaScript projects, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Grunt&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; serves a
similar purpose. It is a JavaScript task/build runner that is written on top of
NodeJS. Grunt can help you with automatically minifying your JavaScript or CSS
files, or reload your browser on every file change. It can show you a
comprehensive list of JavaScript errors, compile your &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;SASS/LESS&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; files into CSS
files automatically, and many other things.&lt;/p&gt;
&lt;p&gt;However, the most significant advantage of Grunt that I am going to discuss
today is its ability to proxy your requests. For example, when you are
developing your backend with anything other than JavaScript, you will face
difficulty in accessing the backend data in your frontend without having to
compile and deploy the code every time you make any changes. It is not possible
with a typical web server setup because
&lt;a href=&quot;https://en.wikipedia.org/wiki/XMLHttpRequest&quot;&gt;XHR&lt;/a&gt; requests are not allowed to
be cross-domain by browsers due to
&lt;a href=&quot;https://en.wikipedia.org/wiki/Cross-origin_resource_sharing&quot;&gt;Cross-origin resource sharing&lt;/a&gt;
(CORS) limitations.&lt;/p&gt;
&lt;p&gt;So, the problem here is as follows,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;you are developing the UI of your applications using some frontend JavaScript
framework (say Angular) with Grunt as the build runner, and the backend of
your application is being designed in some backend framework other than
JavaScript/NodeJS (say Laravel), you might face problems accessing the backend
while running Grunt server.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It happens because the backend Laravel service runs on port 8000, and the front
end development server runs on port 8080. The requests from the frontend server
to the backend-server will result in
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy&quot;&gt;same-origin policy&lt;/a&gt;
errors due to the port difference. To fix this issue, we can set up CORS through
a proxy on Grunt. This proxy will stand in front of your frontend server and the
backend server and get the required data from the backend and pass it to your
frontend while letting your browser think that you are all in the same domain.&lt;/p&gt;
&lt;p&gt;Grunt has a module
&lt;a href=&quot;https://github.com/drewzboto/grunt-connect-proxy&quot;&gt;grunt-connect-proxy&lt;/a&gt; that
exists to help to solve this issue. It delegates requests that match a given URL
to the backend of your choice. So for example, you want to access your backend
using the URL &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;http://localhost:8080/api&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, you can write a proxy rule so that
whenever your user tries to access this URL in a browser, the proxy will get the
data from your backend and server it at this particular URL.&lt;/p&gt;
&lt;p&gt;The procedure to set up the proxy is simple. First, you will have to add the
proxy configuration to your &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Gruntfile.js&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. In this example, I am assuming that
the backend server is running on the port 8000, and the Grunt server is running
on the port 8080. This configuration will delegate all requests to
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;http://localhost:8080/api&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;http://localhost:8000/backend&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;js&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;js&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;connect&lt;/span&gt;: {
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  server&lt;/span&gt;: {
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;    options&lt;/span&gt;: {
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;      port&lt;/span&gt;: 8080,
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;      base&lt;/span&gt;: &apos;public&apos;,
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;      hostname&lt;/span&gt;: &apos;localhost&apos;,
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;      livereload&lt;/span&gt;: true,
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;      middleware&lt;/span&gt;: function (connect, options, middlewares) {
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        middlewares.&lt;/span&gt;unshift(require(&apos;grunt-connect-proxy/lib/utils&apos;).proxyRequest);
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;        return&lt;/span&gt; middlewares;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;    proxies&lt;/span&gt;: [
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        context: &lt;/span&gt;&apos;/api&apos;,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        host: &lt;/span&gt;&apos;localhost&apos;,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        port: &lt;/span&gt;8000,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        https: &lt;/span&gt;false,
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        rewrite: {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;            &apos;^/api&apos;&lt;/span&gt;: &apos;/backend&apos;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    ]&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now register your Grunt server task to run the proxy on Grunt execution.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;js&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;js&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;grunt.&lt;/span&gt;registerTask(&quot;server&quot;, function (target) {
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  grunt.task.&lt;/span&gt;run([&quot;configureProxies:server&quot;, &quot;connect:server&quot;])
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Let me explain the above two scripts line by line. In the connect section of
your &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Gruntfile&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, we add a new section called &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;proxies&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. The options defined in
the proxies section are explained below.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;context&lt;/strong&gt;: This is the context against which the incoming requests will be
matched. Matching requests will be proxied to the backend server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;host&lt;/strong&gt;: The host address where the backend server is running. The incoming
requests will be proxied to this host.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;port&lt;/strong&gt;: The port where the backend server is running.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;https&lt;/strong&gt;: If your backend server is an https endpoint, then set this value to
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;rewrite&lt;/strong&gt;: This option allows rewriting of URL when proxying. What this
means is that when trying to proxy &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;http://localhost:8080/api&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to the backend
server, the URL will be rewritten as &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;http://localhost:8000/backend&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. The
object&apos;s key serves as the regex used in the replacement operation, and the
object&apos;s value is the context of your backend server&apos;s service.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;More options can be found in the
&lt;a href=&quot;https://github.com/drewzboto/grunt-connect-proxy#grunt-connect-proxy&quot;&gt;documentation&lt;/a&gt;
of &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;grunt-connect-proxy&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;You will also need to set up the proxy&apos;s middleware in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;options&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; section of
the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;connect&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. The relevant code is as follows.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;js&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;js&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;...&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;middleware&lt;/span&gt;: function (connect, options, middlewares) {
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  middlewares.&lt;/span&gt;unshift(require(&apos;grunt-connect-proxy/lib/utils&apos;).proxyRequest);
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;  return&lt;/span&gt; middlewares;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Finally, include your proxy task in the server task. It is necessary to append
the proxy task before the connect task. Also, make sure to specify the
connection target in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;configureProxies&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; section. In our case, the connect
target is &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;server&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Now you can start your Grunt server via this configured proxy by typing
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Grunt server&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; in the command line. You should see something like this in the
console.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; grunt server
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;...&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Running&lt;/span&gt; &quot;configureProxies:server&quot; (configureProxies) task
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Rewrite&lt;/span&gt; rule created for: [/^\/api/ -&gt; /backend].
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Proxy&lt;/span&gt; created for: /api to localhost:8000
 
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Running&lt;/span&gt; &quot;connect:server&quot; (connect) task
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Started&lt;/span&gt; connect web server on http://localhost:8080
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The above output confirms that the proxy is working fine. Some of the example
URLs are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;http://127.0.0.1:8080/api&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; points to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;http://127.0.0.1:8000/backend&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;http://127.0.0.1:8080/api/x/y&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; points to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;http://127.0.0.1:8000/backend/x/y&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That&apos;s all. Now you will not face any problems getting data from any backend of
your choice.&lt;/p&gt;</content:encoded></item><item><title>Writing Drozer Modules</title><link>https://yashagarwal.in/notes/writing-drozer-modules/</link><guid isPermaLink="true">https://yashagarwal.in/notes/writing-drozer-modules/</guid><description>Learn to write custom Drozer modules in Python for Android security testing. Explore framework features and practical module development.</description><pubDate>Sun, 13 May 2018 11:40:13 GMT</pubDate><content:encoded>&lt;p&gt;This post is a result of my experimentation with Drozer. Drozer is a security
testing framework for Android, developed by MWR Labs. According the Drozer&apos;s
official
&lt;a href=&quot;https://labs.f-secure.com/assets/BlogFiles/mwri-drozer-user-guide-2015-03-23.pdf&quot;&gt;documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Drozer allows you to assume the role of an Android app and interact with other
apps. It can do anything that an installed application can do, such as making
use of Android&apos;s Inter-Process Communication (IPC) mechanism and interact with
the underlying operating system.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Drozer modules are written in Python. The module performs operations on an
Android device with the help of an agent app installed on the device. The agent
app, by default, has permission to use the internet connection only. This
permission is required so that the agent can open a ServerSocket on port 31415
(default). The agent will listen for the incoming connections on this port. The
console will connect to the agent on this port.&lt;/p&gt;
&lt;p&gt;Drozer modules are inherited Python classes. The parent class is defined in
&lt;a href=&quot;https://github.com/FSecureLABS/drozer/blob/develop/src/drozer/modules/base.py&quot;&gt;drozer.modules.Module&lt;/a&gt;.
Drozer console provides commands to create a custom module repository, which is
very useful for the local development of modules.&lt;/p&gt;
&lt;p&gt;You can read more about the structure of a Drozer module
&lt;a href=&quot;https://github.com/FSecureLABS/drozer/wiki/Writing-a-Module&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I will explain all the critical parts of a Drozer module with the help of a
sample module. I will be implementing a module to record and save the sound from
the inbuilt mic of an Android device.&lt;/p&gt;
&lt;p&gt;I initialized a new module repository using the Drozer console using the
following command.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;dz&gt; module repository create custom&lt;/span&gt;
&lt;span&gt;Initialised repository at custom.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;You will see a new directory &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;custom&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; in your current directory after executing
above command. Navigate to this directory and create a new folder with any name.
I prefer to name this folder same as my module name. In this folder, create a
file &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;__init__.py&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. Drozer identifies the folder as a module directory if
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;__init__.py&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is present in the directory. Now you can implement your module in
this directory.&lt;/p&gt;
&lt;p&gt;To begin implementing our module, create a new file &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;record.py&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; in the module
directory. Drozer has many different utility classes, which we can use to
simplify our implementation. To use these utility classes
(&lt;a href=&quot;https://github.com/FSecureLABS/drozer/wiki/Using-mixins&quot;&gt;mixins&lt;/a&gt;), our module
class must extend &lt;em&gt;mixins&lt;/em&gt; using Python&apos;s multiple inheritance feature.&lt;/p&gt;
&lt;p&gt;We first need to import all the required mixins. The mixins are stored in
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;modules.common&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; package in the Drozer source tree. After importing mixins and
extending our class, the code will look like this. You can also import any other
standard Python module here.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;python&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;python&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;from&lt;/span&gt; drozer.modules import common, Module
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;import&lt;/span&gt; os, subprocess, time
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;class&lt;/span&gt; Record(Module, common.Shell, common.FileSystem, common.ClassLoader):&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now we will set up the metadata for our module. This information will help
Drozer to organize and list our module correctly. We can define the name,
description, author, date, license, path, permissions, and examples. Most of the
available options are self-explanatory. But &lt;em&gt;path&lt;/em&gt; and &lt;em&gt;permissions&lt;/em&gt; require
some explanation.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;path&lt;/em&gt; variable defined here is an array that contains the values for the
namespace of the module. Drozer supports separate namespaces for each module. We
can combine similar modules in the same namespace using this feature.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;permissions&lt;/em&gt; array variable contains all the permissions that this module
will require for proper functioning. For example, our module will need
permission to record audio on the device to work correctly. So we define this
permission in the permissions array. The agent app on the device is required to
have this permission. Otherwise, our module will throw an error.&lt;/p&gt;
&lt;p&gt;The following snippet shows the metadata section of our module.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;name = &quot;Record sound from the inbuilt mic of an Android device.&quot;&lt;/span&gt;
&lt;span&gt;description = &quot;Record sound from the inbuilt mic of an Android device. The default save format is 3GPP. Relies on the agent having the RECORD_AUDIO permission.&quot;&lt;/span&gt;
&lt;span&gt;examples = &quot;&quot;&quot;&lt;/span&gt;
&lt;span&gt;dz&gt; run custom.record.record&lt;/span&gt;
&lt;span&gt;Setting up recorder configuration...&lt;/span&gt;
&lt;span&gt;Recording started&lt;/span&gt;
&lt;span&gt;Press any key to stop recording&lt;/span&gt;
 
&lt;span&gt;Recording stopped...downloading recording&lt;/span&gt;
&lt;span&gt;Screenshot captured. Saved at location /home/yash/work/drozer/1524201166.3gp&lt;/span&gt;
&lt;span&gt;&quot;&quot;&quot;&lt;/span&gt;
&lt;span&gt;author: &quot;Yash Agarwal&quot;&lt;/span&gt;
&lt;span&gt;date: &quot;2018-04-14&quot;&lt;/span&gt;
&lt;span&gt;license = &quot;BSD (3 clause)&quot;&lt;/span&gt;
&lt;span&gt;path = [&quot;custom&quot;, &quot;record&quot;]&lt;/span&gt;
&lt;span&gt;permissions = [&quot;android.permission.RECORD_AUDIO&quot;, &quot;com.mwr.dz.permissions.GET_CONTEXT&quot;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now we can start implementing the heart of our module, the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;execute()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; function.
This function will be invoked by Drozer when the module is run. Every action
that the module is expected to perform should be implemented in this method.&lt;/p&gt;
&lt;p&gt;The implementation of &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;execute()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; method is slightly tricky and requires an
understanding of different classes and methods provided by the Android API. As
we are writing a module to record sound, we will look into the documentation of
&lt;a href=&quot;https://developer.android.com/guide/topics/media/mediarecorder.html&quot;&gt;MediaRecorder&lt;/a&gt;
class. Before reading further, go through the documentation about the use of
reflection API in Drozer
&lt;a href=&quot;https://github.com/FSecureLABS/drozer/wiki/Using-Reflection&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;execute()&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; function is given below.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;python&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;python&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;def&lt;/span&gt; execute(self, arguments):
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    # unique file names&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    filename &lt;/span&gt;= str(int(time.time())) + &quot;.3gp&quot;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    # current working directory of Drozer console&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    cwd &lt;/span&gt;= self.workingDir()
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    # Magic of Reflection API !!!&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    recorder &lt;/span&gt;= self.new(&quot;android.media.MediaRecorder&quot;)
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    AudioSource &lt;/span&gt;= self.klass(&quot;android.media.MediaRecorder$AudioSource&quot;)
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    OutputFormat &lt;/span&gt;= self.klass(&quot;android.media.MediaRecorder$OutputFormat&quot;)
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    AudioEncoder &lt;/span&gt;= self.klass(&quot;android.media.MediaRecorder$AudioEncoder&quot;)
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    recorder.setAudioSource(AudioSource.&lt;/span&gt;MIC)
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    recorder.setOutputFormat(OutputFormat.&lt;/span&gt;THREE_GPP)
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    recorder.setAudioEncoder(AudioEncoder.&lt;/span&gt;AMR_NB)
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    recorder.setOutputFile(&lt;/span&gt;&quot;%s/recording.3gp&quot; % cwd)
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    recorder.prepare()&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;    self&lt;/span&gt;.stdout.write(&quot;Recording started\n&quot;)
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    recorder.start()&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#E36209&quot;&gt;    raw_input&lt;/span&gt;(&quot;Press any key to stop recording\n&quot;)
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    recorder.stop()&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;    self&lt;/span&gt;.stdout.write(&quot;Recording stopped...\n&quot;)
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    recorder.reset()&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    recorder.release()&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;    # Download file from device to PC&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    length &lt;/span&gt;= self.downloadFile(&quot;%s/recording.3gp&quot; % cwd, filename)
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    if&lt;/span&gt; length != None:
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;        self&lt;/span&gt;.stdout.write(&quot;Recording saved\n&quot;)
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    else&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;        self&lt;/span&gt;.stderr.write(&quot;Recording could not be fetched from the device.\n&quot;)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;I followed the sample use case given on
&lt;a href=&quot;https://developer.android.com/reference/android/media/MediaRecorder.html&quot;&gt;this&lt;/a&gt;
page, to instantiate and use the &lt;em&gt;MediaRecorder&lt;/em&gt; object.&lt;/p&gt;
&lt;p&gt;After the recording is finished, we want to save this recorded media file to our
computer. Drozer provides a method,
&lt;a href=&quot;https://github.com/FSecureLABS/drozer/blob/c92d74024c653b6dc7de3378a24e51d276ae2c62/src/drozer/modules/common/file_system.py&quot;&gt;downloadFile&lt;/a&gt;
exactly for this purpose. This method returns the length of the data downloaded
on success and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;None&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; otherwise. We can use this information to test the success
or failure of the fetching of the recording.&lt;/p&gt;
&lt;p&gt;That&apos;s all. We have successfully implemented a Drozer module which can record
the sound on an Android device without the knowledge of the user. Do you smell
something fishy here? The whole idea here depends on that particular
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;android.permission.RECORD_AUDIO&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; permission that our agent app had. It allowed
our module to record without &lt;em&gt;user consent&lt;/em&gt; (actually, the user gave her consent
unknowingly while installing agent app). Many apps nowadays ask for arbitrarily
random permissions. Those permissions might not be related to the functionality
of the app in any way, but because there is no method to install apps without
granting these permissions, the users grant all permissions to these apps. That
can be exploited very easily. This tutorial tried to show one of such
exploitations.&lt;/p&gt;
&lt;p&gt;Here are some exercises that you should try if you want to learn more about
Drozer module development.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A module to initiate a call on a device.&lt;/li&gt;
&lt;li&gt;A module to get the clipboard values on a device&lt;/li&gt;
&lt;li&gt;Try finding a public exploit on Android forums such as XDA and implement that
exploit as a Drozer module.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Slightly tougher one.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A module to terminate a call without user intervention (I do not know if it is
possible to do this programmatically. If you implement this successfully, do
let me know in the comments section.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks for reading. Cheers :)&lt;/p&gt;</content:encoded></item><item><title>So I Applied for GSoC</title><link>https://yashagarwal.in/notes/so-i-applied-for-gsoc/</link><guid isPermaLink="true">https://yashagarwal.in/notes/so-i-applied-for-gsoc/</guid><description>Explore the personal journey of applying for Google Summer of Code. Learn about overcoming self-doubt and contributing to open-source development.</description><pubDate>Wed, 28 Mar 2018 15:28:26 GMT</pubDate><content:encoded>&lt;p&gt;I first heard about Google Summer of Code (GSoC) in my second year (2016). It
was quite fascinating to know that such a program exists (possibly because of
that super attractive amount of money, $5500 at that time). I researched about
it and sent emails to some mentors. The replies were mostly encouraging, but I
still could not gather the courage to apply as I used to doubt my capabilities.
Then last year (2017) again, I decided that I should try for GSoC one more time.
I looked for the projects, started reading codebase of one project, but due to
my lack of determination, I again did not apply.&lt;/p&gt;
&lt;p&gt;In the summers of 2017, I got some time to think about it. I decided that for
the next year, I will try everything to make sure that I apply for GSoC 2018. I
started coding as much as possible and pushing my code to GitHub to build an
impressive profile.&lt;/p&gt;
&lt;p&gt;Now I can say that I am satisfied with my efforts to some extent. I did start
some good &lt;a href=&quot;https://github.com/yashhere/BeautifyMP3&quot;&gt;open&lt;/a&gt;
&lt;a href=&quot;https://github.com/yashhere/ConMan&quot;&gt;source&lt;/a&gt;
&lt;a href=&quot;https://github.com/yashhere/Goofy&quot;&gt;projects&lt;/a&gt;. They are not very extraordinary,
but something is better than nothing. I dived into Debian packaging also and
volunteered for a FOSS event. Spreading awareness about FOSS is also
contributing to FOSS. Isn&apos;t it?&lt;/p&gt;
&lt;p&gt;Coming back to GSoC, this year, I have successfully submitted a proposal to the
Debian Project. It does not matter whether I get it or not. I overcame one of my
biggest fears of doubting my capabilities. It is something that I was trying to
do for the last two years. This moment is worth celebrating.&lt;/p&gt;
&lt;p&gt;Read about my GSoC project on
&lt;a href=&quot;https://wiki.debian.org/SummerOfCode2018/Projects#SummerOfCode2018.2FProjects.2FBootTorrent.Boot_many_machines_via_bittorrent&quot;&gt;Boot Many Machines via Bittorrent&lt;/a&gt;.
It is related to something which I learned in &lt;a href=&quot;http://athena.nitc.ac.in/&quot;&gt;SSL&lt;/a&gt;
as SSL admin.&lt;/p&gt;
&lt;p&gt;Read my project proposal on
&lt;a href=&quot;https://wiki.debian.org/YashAgarwal/GSoCProposal&quot;&gt;Debian Wiki&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/gsoc-timeline.UvjsyvGF_Z1GGSOn.webp&quot; alt=&quot;gsoc timeline&quot; title=&quot;gsoc timeline&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;826&quot; height=&quot;165&quot;&gt;&lt;/p&gt;
&lt;p&gt;Eagerly waiting for the results. 😄&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update(24/04/2018)&lt;/strong&gt;: Finally, I did not get into GSoC this time too. No
worries. I anticipated the results and prepared backup plans. Looking forward to
a productive summer. :)&lt;/p&gt;</content:encoded></item><item><title>FOSSMeet&apos;18</title><link>https://yashagarwal.in/notes/fossmeet-18/</link><guid isPermaLink="true">https://yashagarwal.in/notes/fossmeet-18/</guid><description>A retrospective on FOSSMeet&apos;18, sharing personal experiences, challenges, and insights gained as a volunteer and FOSSCell secretary.</description><pubDate>Mon, 26 Mar 2018 06:27:14 GMT</pubDate><content:encoded>&lt;p&gt;I know I am very late in writing this post. It has been almost one and a half
months since the last edition of FOSSMeet is over. I have been a part of
FOSSMeet both as a participant and a volunteer. I want to share some of my
observations, views, and suggestions through this post. I intend to keep a
memory of my most favorite event of NIT Calicut. Juniors can read this post and
think about ways to improve FOSSCell and FOSSMeet. I did the same by reading
Kartik&apos;s
&lt;a href=&quot;http://techglider.in/post/2013/04/14/of-fossmeets-at-nit-calicut/&quot;&gt;post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before I start, if you have not read my &lt;em&gt;post&lt;/em&gt; on the 2017 edition of the
FOSSMeet, it is a good time to read that first. This post is going to be a
follow up from where I stopped that post. &lt;a href=&quot;https://yashagarwal.in/notes/fossmeet-17/&quot;&gt;Here&lt;/a&gt; is the link
to that post.&lt;/p&gt;
&lt;p&gt;I&apos;ll start by quoting some lines from the last paragraph of that article.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I hope that I will find time next year for FOSSMeet, although I would prefer
to attend FOSSMeet as a participant observing everything silently rather than
being a part of the organizing team.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;These were my views after last year&apos;s FOSSMeet. I felt that I was not getting
any benefit from volunteering for FOSSMeet. It is one thing that you help
conducting an event, but on a personal level, I was not learning much. I wanted
to attend talks and learn about free software philosophies, but because I was
busy volunteering for workshops in &lt;em&gt;SSL&lt;/em&gt;, I could not participate in any
lecture. So I wanted to make sure that in my last FOSSMeet, I do attend all the
talks and learn something new.&lt;/p&gt;
&lt;p&gt;But fate had its plans for me. Few days after writing that post, Simsar, the
coordinator of FOSSMeet &apos;17, came to my room and asked me if I would like to
become the next secretary of FOSSCell. Those who don&apos;t know, FOSSCell is the
group of people in NITC, who are supposed to work on free and open-source
contribution. But it is not very active for the last few years. Probably the
seniors decided to give me a chance because I was quite active in providing my
suggestions for the FOSSCell when I was in the third year and had shown my
intentions to reinitiate FOSSCell. Anyway, I was not very enthusiastic about
this opportunity and &lt;em&gt;refused&lt;/em&gt; to accept it. I thought that the topic was closed
and did not bother about it much.&lt;/p&gt;
&lt;p&gt;Fast forward two months, I was at home thinking about the reasons that I could
not get an internship were. I figured out some reasons (a topic reserved for a
later post!) and decided that whatever happens, I will not commit these mistakes
again. A few days later, Simsar messaged me on WhatsApp, asking whether I am
still interested in the post of secretary. This time, I immediately accepted his
offer. I was under the influence of my learnings from past mistakes. And that&apos;s
how I became the unexpected (at least for my batchmates) secretary of FOSSCell.&lt;/p&gt;
&lt;p&gt;I was placed in the first few days of placement season, so I was free on that
front. CSEA had conducted a Debian packaging workshop at the very beginning of
the semester, but I could not attend that workshop. So I messaged Pirate Praveen
sir privately and asked him whether he can guide me about Debian packaging. As
with most of the senior open source contributors, he was very enthusiastic about
helping me. So that&apos;s how I restarted my journey in open source. It was a fun
time learning about free software ideology from Pirate Praveen. We decided to
conduct a small Debian Packaging hackathon in NITC. As it is a norm in CSE NITC
nowadays about any such activity, people did not turn up at all for this
hackathon. Only five people showed up for the hackathon. That was disappointing.
Though, on a personal level, I was satisfied. I submitted two packages to the
Debian unstable repository. We did not have any other activity for the remaining
of that semester.&lt;/p&gt;
&lt;p&gt;Okay, enough of the background!&lt;/p&gt;
&lt;h1 id=&quot;my-observations&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#my-observations&quot;&gt;My Observations&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We opted for the &lt;a href=&quot;https://talkfunnel.com/&quot;&gt;HasGeek&apos;s Funnel&lt;/a&gt; for the proposal
acceptance this time also. The funnel works quite well for our workflow. We did
not get many &lt;a href=&quot;https://fossmeet-nitc.talkfunnel.com/2018/&quot;&gt;proposals&lt;/a&gt; in the
beginning. I had read somewhere on the web that FOSSMeet had a MiniDebConf once.
That seemed like an excellent idea to the team. So I talked with Praveen sir,
about the possibility of a separate Debian track during FOSSMeet. I thought that
Debian packaging might be a good and easy way to introduce NITC students to
Open-source software.&lt;/p&gt;
&lt;p&gt;In previous editions of FOSSMeets, the organizers used to receive the
&lt;a href=&quot;http://techglider.in/post/2013/04/14/of-fossmeets-at-nit-calicut/&quot;&gt;feedback&lt;/a&gt;
that the student audience is entirely novice for some sessions and the
supposedly advanced session turned out to be a beginner session. We were well
aware of this problem and thought of a way to solve this. The solution may be a
controversial one because even I have mixed feelings about this solution. We
decided to look at the GitHub profiles of each participant and then select a few
participants rather than allowing each and everyone who is paying money to
attend the FOSSMeet. Our experience from last year was awful in this aspect.
Students from various colleges of Kerala came to FOSSMeet just to get the
certificate. Such an audience was not contributing anything to FOSSMeet.&lt;/p&gt;
&lt;p&gt;Now, let me explain why I think that this is not the right way to filter good
participants. If I am not wrong, one motive behind organizing such &lt;em&gt;student run
conferences&lt;/em&gt; is to inspire beginners and college students to learn about free
and open-source software and to allow them to learn about new technologies. Now,
it should not matter if the person has any prior experience or not. In our case,
we prioritized the &lt;em&gt;previous experience&lt;/em&gt; part and neglected &lt;em&gt;the will to learn&lt;/em&gt;.
I know that it is tough to identify if a person is really interested in the
event or just coming for the certificate, but still, there must be some better
way to solve this issue. For now, this method is the best option available, and
it worked well enough for our purpose.&lt;/p&gt;
&lt;p&gt;The decision to allow only 150 participants was an excellent move. We had
decided not to have parallel workshops and talks. This decision was a direct
outcome of some of the bad feedback from the previous FOSSMeets. The decisions
to check GitHub profiles and to restrict the number of participants made sure
that this edition of FOSSMeet has the most appropriate (read qualified) audience
for any session.&lt;/p&gt;
&lt;p&gt;We publicized the event among CSED&apos;s first years. We even had a beginner level
Git workshop for them. We were expecting that they will come to take part in the
event. These events provide excellent opportunities for newcomers to learn about
Computer Science and its various fields. I used to give priority to a CSEA event
over any cultural event when I was in my first year. But, the turnout of
first-year students for FOSSMeet was very less. I sometimes worry, how are these
people going to continue organizing FOSSMeet. In the end, conducting this event
will become a burden (of carrying a legacy) for them, and they will hold this
event just like any other useless event that happens in NITC every weekend. We
even made the entry, free for them; still, if they don&apos;t feel interested in the
event, then they are at an apparent loss.&lt;/p&gt;
&lt;p&gt;One other complaint that we received from the community was that the procedure
of selecting proposals from the funnel is not transparent. &lt;em&gt;In my opinion&lt;/em&gt;, it
is true. The organizing team of FOSSMeet sit together and choose the topics
based on the relevance of the topics and its relation to FOSS ideologies. Most
of the proposals in the funnel were related to some technology or programming
language. We aimed to give a chance to the talks which explain more about free
software in general. Most of the proposals selected this year revolved around
this theme with one or two exceptions. But I think it might be a good idea to
publicly tell the factors that are taken into account while selecting proposals.
FOSSMeet is an event about free software and the community, and it is the
responsibility of the organizers to make sure that they adhere to the ideologies
of free software, including transparency.&lt;/p&gt;
&lt;p&gt;The decision to select philosophical topics might seem like a great thing.
Still, in reality, the student audience is not very interested in listening to
some random guy preaching about something which is not very relevant to them.
Students want more technical knowledge, which they can get only from technical
talks and workshops. I hope that future FOSSMeet organizers will be more careful
about maintaining the right balance between technical and not technical
discussions and workshops.&lt;/p&gt;
&lt;p&gt;Some students from Amrita college complained about our selection of the same
speakers every year. In my opinion, it is a very valid complaint. In my last
three FOSSMeets, almost 3-5 speakers are giving talks/workshops every year. I am
not saying that it is bad in any way, but the organizing team can start a bit
early and invite some other prominent faces of the field from different parts of
the country. The issue is that we begin contacting speakers very late and the
people coming from far corners of the country or from abroad get very little
time for making arrangements.&lt;/p&gt;
&lt;p&gt;We used to have panel discussions in FOSSMeet. For the last two years, we
stopped having one. I think that a panel discussion is a great way to learn
about different viewpoints of experienced people. It will be good if the future
organizers can squeeze one such panel discussion in the FOSSMeet schedule.&lt;/p&gt;
&lt;p&gt;Now coming to my memories of this edition of the event, I liked the video
conference by Bradley M Kuhn, the president of the Software Freedom Conservancy.
The way he explained current issues in software freedom was fascinating. I was
amazed by his humbleness. I was looking forward to the talk by RMS, but he could
not deliver his speech due to some technical issues.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On a lighter note&lt;/strong&gt;, It feels strange when you are working in a team where
everyone except you speaks a language that you don&apos;t understand. I know that it
is a very natural behavior, and I have no &lt;em&gt;complains&lt;/em&gt; about it. But in my
opinion, language is a tool of communication, and when you are not able to
communicate your views to others, then there is some problem. When I think about
these issues, I admire the forefathers of India for their farsightedness to make
a &lt;em&gt;foreign&lt;/em&gt; but &lt;em&gt;universal&lt;/em&gt; language, one of the official languages of the
Republic of India.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I feel at a loss because I got the chance to attend only three FOSSMeets (2015
edition never came to reality). It has been a great experience both as a
participant and a volunteer for me over the last three years. I have written two
posts about FOSSMeets and have tried to cover everything which I liked or
disliked about this event. I might be very &lt;em&gt;biased&lt;/em&gt; in the views expressed here
as I was very disappointed with the lack of any activity from the FOSSCell side
to introduce students about open source contributions. My &lt;em&gt;lack&lt;/em&gt; of good
communication skills made sure that the trend continues in my tenure also. I
wish good luck to the next office bearers and hope that they will not continue
this trend. 😄&lt;/p&gt;
&lt;p&gt;Thanks to all fourth years – Sajmal, &lt;strong&gt;Navaneeth&lt;/strong&gt;, Nithin, Kumar, Pavithra,
Vrushabh, Nitin, and others for making the FOSSMeet a success. All the best to
all juniors – Abhiram, Archana, Olive, Amruth, Gazala, Abhirami, Anupam,
Madhumita, Adil, Vysakh, Arun, and others. Special mention to some second years
also – Nirmal, Faris, Darshana, Kavitha, Naina, Vishnu, and others for helping
us out in a smooth organization of the event.&lt;/p&gt;
&lt;p&gt;Feeling relieved now, as this long overdue post is finally complete. If you find
the article interesting, share your views in the comments section. Thanks for
reading. 😌&lt;/p&gt;</content:encoded></item><item><title>Deactivated My Facebook Account</title><link>https://yashagarwal.in/notes/deactivated-my-facebook-account/</link><guid isPermaLink="true">https://yashagarwal.in/notes/deactivated-my-facebook-account/</guid><description>A personal reflection on deactivating Facebook for a digital detox, exploring its impact on productivity, social life, and self-introspection.</description><pubDate>Fri, 23 Mar 2018 15:30:44 GMT</pubDate><content:encoded>&lt;p&gt;Today, I deactivated my Facebook account again. For the last few days, I was
feeling that I am using Facebook excessively. It was affecting my work, my
&lt;em&gt;public life&lt;/em&gt;. I was using Facebook day in and day out. Today when I woke up in
the morning, I first opened Facebook and didn&apos;t leave my bed for one hour. I
realized that I had wasted one hour merely browsing through useless stuff.
Immediately, I decided to deactivate the account for some time and analyze how
much my life changes by one less distraction.&lt;/p&gt;
&lt;p&gt;Coincidentally, it is the time of &lt;a href=&quot;http://ragam.org.in/Main/&quot;&gt;Ragam&lt;/a&gt;, the annual
cultural festival of NIT Calicut. I &lt;em&gt;introspect&lt;/em&gt; myself every year at the same
time. For the last two years, this introspection is resulting in the
deactivation of my Facebook account. It is the reason why I could finish all my
pending projects in the summers.&lt;/p&gt;
&lt;p&gt;I sometimes feel that after coming to NITC, I have become much more socially
awkward and even more of a loner than I was before. I never enjoyed going into
public events, but in college, that tendency seems to have increased a lot. Now,
I do not feel comfortable with this state. I want to change this, but every time
I try, there is some &lt;em&gt;invisible force&lt;/em&gt; which pulls me back from expressing
myself. NITC&apos;s environment was entirely different for a person like me, who
always preferred to stay alone. So, I built a &lt;em&gt;bubble&lt;/em&gt; around myself, where
there is no one to disturb or doubt me. It was okay in the initial years of my
campus life when circumstances were not in my favor, but now this bubble is an
obstacle for me. I feel difficulty in coming out of this bubble.&lt;/p&gt;
&lt;p&gt;There are only one and a half months left of my undergraduate life. I might not
overcome this fear at this time. But I hope that the change of environment will
help me cross this barrier. I have learned a lot of lessons from my mistakes in
the past, and I hope that I will not repeat one of the biggest mistakes of my
life.&lt;/p&gt;
&lt;p&gt;I will write again about the changes I feel after deactivating Facebook. In the
meantime, I will try to spend more time with my friends and less on my laptop.
😌&lt;/p&gt;</content:encoded></item><item><title>Develop a Theme for Hugo</title><link>https://yashagarwal.in/notes/develop-a-theme-for-hugo/</link><guid isPermaLink="true">https://yashagarwal.in/notes/develop-a-theme-for-hugo/</guid><description>Learn to develop a basic Hugo theme, understanding Go templating, content organization, and static site generation for your blog.</description><pubDate>Fri, 02 Mar 2018 05:57:05 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;This article was originally published on
&lt;a href=&quot;https://www.zeolearn.com/magazine/develop-a-theme-for-hugo&quot;&gt;zeolearn&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h1 id=&quot;introduction&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;In this tutorial, I will show you how to create a basic Hugo theme. I assume
that you are familiar with basic HTML, and how to write content in markdown. I
will be explaining the working of Hugo and how it uses Go templating language
and how you can use these templates to organize your content. As this post will
be focusing mainly on Hugo&apos;s working, I will not be covering CSS here.&lt;/p&gt;
&lt;p&gt;We will be starting with some necessary information about the terminology used
in Hugo. Then we will create a Hugo site with a very basic template. Then we
will add new templates and posts to our site as we delve further into Hugo. With
very slight variations to what you will learn here, you will be able to create
different types of real-world websites.&lt;/p&gt;
&lt;p&gt;Now, a short tutorial about the flow of this post. The commands that start with
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;$&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; are meant to be run in the terminal or command line. The output of the
command will follow immediately. Comments will begin with &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;h1 id=&quot;some-terminology&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#some-terminology&quot;&gt;Some Terminology&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&quot;configuration-file&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#configuration-file&quot;&gt;Configuration File&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hugo uses a configuration file to identify common settings for your site. It is
located in the root of your site. This file can be written in TOML, YAML or JSON
formats. Hugo identifies this file using the extension.&lt;/p&gt;
&lt;p&gt;By default, Hugo expects to find Markdown files in your &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;content/&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; directory and
template files in your &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;themes/&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; directory. It will create HTML files in your
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;public/&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; directory. You can change this by specifying alternate locations in
the configuration file.&lt;/p&gt;
&lt;h2 id=&quot;content&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#content&quot;&gt;Content&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The content files will contain the metadata and text about your posts. A content
file can be divided into two sections, the top section being frontmatter and the
next section is the markdown that will be converted to HTML by Hugo. The content
files reside in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/content&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; directory.&lt;/p&gt;
&lt;h2 id=&quot;frontmatter&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#frontmatter&quot;&gt;Frontmatter&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The frontmatter section contains information about your post. It can be written
in JSON, TOML or YAML. Hugo identifies the type of frontmatter used with the
help of identifying tokens(markers). TOML is surrounded by &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;---&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, YAML is by
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;---&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and JSON is enclosed in curly braces &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. The information in the
front matter of a content type will be parsed to be used in the template for
that specific content type while converting to HTML.&lt;/p&gt;
&lt;p&gt;I prefer to use YAML, so you might need to translate your configurations if you
are using JSON or TOML.&lt;/p&gt;
&lt;p&gt;This is an example of frontmatter written in YAML.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;---&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;date&lt;/span&gt;: &quot;2018-02-11T11:45:05+05:30&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;title&lt;/span&gt;: &quot;Basic Hugo Theming Tutorial.&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;description&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;  &quot;A primer about theme development for Hugo, a static site generator written in&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;  Golang.&quot;&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;categories&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  - &lt;/span&gt;Hugo
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  - &lt;/span&gt;Customization
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;tags&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  - &lt;/span&gt;Theme
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;---&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;You can read more about different configuration options available for
frontmatter &lt;a href=&quot;https://gohugo.io/content-management/front-matter/#readout&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;markdown&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#markdown&quot;&gt;Markdown&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The markdown section is where you will write your actual post. The content
written here will automatically be converted to HTML by Hugo with the help of a
Markdown engine.&lt;/p&gt;
&lt;h2 id=&quot;templates&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#templates&quot;&gt;Templates&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In Hugo, templates govern the way; your content will be rendered to HTML. Each
template provides a consistent layout when rendering the markdown content. The
templates reside in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/layouts&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; directory.&lt;/p&gt;
&lt;p&gt;There are three types of templates: &lt;em&gt;single&lt;/em&gt;, &lt;em&gt;list&lt;/em&gt; and &lt;em&gt;partial&lt;/em&gt;. Each kind of
template take some content as input and transform it according to the way
defined in the template.&lt;/p&gt;
&lt;h3 id=&quot;single-template&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#single-template&quot;&gt;Single Template&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A single template is used to render a single page. The best example of this is
&lt;em&gt;about&lt;/em&gt; page.&lt;/p&gt;
&lt;h3 id=&quot;list-template&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#list-template&quot;&gt;List Template&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A list template renders a group of related content. It can be all recent posts
or all posts belonging to a particular category.&lt;/p&gt;
&lt;p&gt;The homepage template is a specific type of list template. Hugo assumes that the
homepage will serve as a bridge to all the other content on your website.&lt;/p&gt;
&lt;h2 id=&quot;partials&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#partials&quot;&gt;Partials&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Partials are short code snippets that can be injected in any other template
type. They are instrumental when you want to repeat some content on every page
of your website. The header and footer content are good candidates to be
included in separate partials. It is a good practice to use partials liberally
in your Hugo site as it adheres to
&lt;a href=&quot;https://en.wikipedia.org/wiki/Don%27t_repeat_yourself&quot;&gt;DRY&lt;/a&gt; principle.&lt;/p&gt;
&lt;h1 id=&quot;okay-lets-start&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#okay-lets-start&quot;&gt;Okay, Let&apos;s Start&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;So now that you have a basic understanding of Hugo, we will create a new site
using Hugo. Hugo provides a command to generate new sites. We will use that
command to scaffold our site. It will create a basic skeleton of your site and
will give you a basic configuration file.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; hugo new site ~/zeo
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; cd ~/zeo
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; ls -l
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;total&lt;/span&gt; 28
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;drwxr-xr-x&lt;/span&gt; 2 yash hogwarts 4096 Feb 11 11:13 archetypes
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;-rw-r--r--&lt;/span&gt; 1 yash hogwarts   82 Feb 11 11:13 config.toml
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;drwxr-xr-x&lt;/span&gt; 2 yash hogwarts 4096 Feb 11 11:13 content
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;drwxr-xr-x&lt;/span&gt; 2 yash hogwarts 4096 Feb 11 11:13 data
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;drwxr-xr-x&lt;/span&gt; 2 yash hogwarts 4096 Feb 11 11:13 layouts
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;drwxr-xr-x&lt;/span&gt; 2 yash hogwarts 4096 Feb 11 11:13 static
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;drwxr-xr-x&lt;/span&gt; 2 yash hogwarts 4096 Feb 11 11:13 themes&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I will use YAML format for the config file. Hugo, By default, uses
TOML format.&lt;/p&gt;
&lt;p&gt;A small description of this directory structure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;archetypes&lt;/strong&gt;: The archetypes contains predefined frontmatter format for your
website&apos;s content types. It facilitates consistent metadata format across all
the content of your site.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;content&lt;/strong&gt;: The content directory contains the markdown files that will be
converted to HTML and served to the user.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;data&lt;/strong&gt;: From Hugo documentation&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The data folder is where you can store additional data for Hugo to use when generating your site. Data files are not used to generate standalone pages; rather, they are meant to be supplemental to content files. This feature can extend the content in case your front matter fields grow out of control. Or perhaps you want to show a larger dataset in a template (see example below). In both cases, it is a good idea to outsource the data in their files.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;layouts&lt;/strong&gt;: The layouts folder stores all the templates files which form the
presentation of the content files.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;static&lt;/strong&gt;: The static folder will contain all the static assets such as
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;CSS&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;JS&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;image&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; files.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;themes&lt;/strong&gt;: The themes folder is where we will be storing our theme.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We will edit the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;config.yaml&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file to edit some basic configuration of the
site.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; vim config.yaml
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;baseURL:&lt;/span&gt; /
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;title:&lt;/span&gt; &quot;My First Blog&quot;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;defaultContentLanguage:&lt;/span&gt; en
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;languages:&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  en:&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;    lang:&lt;/span&gt; en
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;    languageName:&lt;/span&gt; English
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;    weight:&lt;/span&gt; 1
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;MetaDataFormat:&lt;/span&gt; &quot;yaml&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now when you run your site, Hugo will show some errors. It is normal because our
layouts and themes directories are still empty.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; hugo --verbose
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;INFO&lt;/span&gt; 2018/02/11 11:20:59 Using config file: /home/yash/zeo/config.yaml
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Building&lt;/span&gt; sites ... INFO 2018/02/11 11:20:59 syncing static files to /home/yash/zeo/public/
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;WARN&lt;/span&gt; 2018/02/11 11:20:59 No translation bundle found for default language &quot;en&quot;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;WARN&lt;/span&gt; 2018/02/11 11:20:59 Translation func for language en not found, use default.
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;WARN&lt;/span&gt; 2018/02/11 11:20:59 i18n not initialized, check that you have language file (in i18n) that matches the site language or the default language.
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;WARN&lt;/span&gt; 2018/02/11 11:20:59 [en] Unable to locate layout for &quot;taxonomyTerm&quot;:
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;...&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This command will also create a new directory called &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;public/&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. This is the
directory where Hugo will save all the generated HTML files related to your
site. It also stores all static data in this folder.&lt;/p&gt;
&lt;p&gt;Let&apos;s have a look at the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;public&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; folder.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; ls -l public/
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;total&lt;/span&gt; 16
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;drwxr-xr-x&lt;/span&gt; 2 yash hogwarts 4096 Feb  11 11:22 categories
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;-rw-r--r--&lt;/span&gt; 1 yash hogwarts  400 Feb  11 11:25 index.xml
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;-rw-r--r--&lt;/span&gt; 1 yash hogwarts  383 Feb  11 11:25 sitemap.xml
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;drwxr-xr-x&lt;/span&gt; 2 yash hogwarts 4096 Feb  11 11:22 tags&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Hugo generated some XML files, but there are no HTML files. It is because we
have not created any content in our content directory yet.&lt;/p&gt;
&lt;p&gt;At this point, you have a working site with you. All that is left is to add some
content and a theme to your site.&lt;/p&gt;
&lt;h2 id=&quot;create-a-new-theme&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#create-a-new-theme&quot;&gt;Create a new theme&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hugo doesn&apos;t ship with a default theme. There are a lot of themes available on
Hugo website. Hugo also ships with a command to create new themes.&lt;/p&gt;
&lt;p&gt;In this tutorial, we will be creating a theme called &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;zeo&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. As mentioned
earlier, my aim is to show you how to use Hugo&apos;s features to fill out your HTML
files from the markdown content, I will not be focusing on CSS. So the theme
will be ugly but functional.&lt;/p&gt;
&lt;p&gt;Let&apos;s create a basic skeleton of the theme. It will create the directory
structure of the theme and place empty files for you to fill in.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# run it from the root of your site&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; hugo new theme zeo
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; ls -l themes/zeo/
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;total&lt;/span&gt; 20
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;drwxr-xr-x&lt;/span&gt; 2 yash hogwarts 4096 Feb 11 11:30 archetypes
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;drwxr-xr-x&lt;/span&gt; 4 yash hogwarts 4096 Feb 11 11:30 layouts
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;-rw-r--r--&lt;/span&gt; 1 yash hogwarts 1081 Feb 11 11:30 LICENSE.md
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;drwxr-xr-x&lt;/span&gt; 4 yash hogwarts 4096 Feb 11 11:30 static
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;-rw-r--r--&lt;/span&gt; 1 yash hogwarts  432 Feb 11 11:30 theme.toml&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Fill out &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;LICENSE.md&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;theme.toml&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file if you plan to distribute your theme
to outside world.&lt;/p&gt;
&lt;p&gt;Now we will edit our &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;config.yaml&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file to use this theme.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; vim config.yaml
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;theme:&lt;/span&gt; &quot;zeo&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now that we have an empty theme, let&apos;s build the site.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; hugo --verbose
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;INFO&lt;/span&gt; 2018/02/11 11:34:14 Using config file: /home/yash/zeo/config.yaml
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Building&lt;/span&gt; sites ... INFO 2018/02/11 11:34:14 syncing static files to /home/yash/zeo/public/
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;WARN&lt;/span&gt; 2018/02/11 11:34:14 No translation bundle found for default language &quot;en&quot;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;WARN&lt;/span&gt; 2018/02/11 11:34:14 Translation func for language en not found, use default.
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;WARN&lt;/span&gt; 2018/02/11 11:34:14 i18n not initialized, check that you have language file (in i18n) that matches the site language or the default language.
 
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;                   |&lt;/span&gt; EN
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;+------------------+----+&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  Pages&lt;/span&gt;            |  3
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  Paginator&lt;/span&gt; pages  |  0
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  Non-page&lt;/span&gt; files   |  0
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  Static&lt;/span&gt; files     |  0
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  Processed&lt;/span&gt; images |  0
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  Aliases&lt;/span&gt;          |  0
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  Sitemaps&lt;/span&gt;         |  1
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  Cleaned&lt;/span&gt;          |  0
 
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Total&lt;/span&gt; in 12 ms&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;These warnings are harmless in our case, as we are developing our site in
English only.&lt;/p&gt;
&lt;p&gt;Hugo does two things while generating your website. It transforms all the
content files to HTML using the defined templates, and its copies static files
into the site. Static files are not transformed by Hugo. They are copied exactly
as they are.&lt;/p&gt;
&lt;h2 id=&quot;the-cycle&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-cycle&quot;&gt;The Cycle&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The usual development cycle when developing themes for Hugo is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Delete the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/public&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; folder&lt;/li&gt;
&lt;li&gt;Run the built-in web server and open your site in the browser&lt;/li&gt;
&lt;li&gt;Make changes to your theme files&lt;/li&gt;
&lt;li&gt;View your changes in browser&lt;/li&gt;
&lt;li&gt;Repeat step 3&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is necessary to delete the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;public&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; directory because Hugo does not try to
remove any outdated files from this folder. So the old data might interfere with
your workflow.&lt;/p&gt;
&lt;p&gt;It is also a good idea to track changes in your theme with the help of a version
control software. I prefer Git for this. You can use others according to your
preference.&lt;/p&gt;
&lt;h2 id=&quot;run-your-site-in-the-browser&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#run-your-site-in-the-browser&quot;&gt;Run your site in the browser&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hugo has a built-in web server which helps considerably while developing themes
for Hugo. It also has a &lt;em&gt;live reload&lt;/em&gt; and &lt;em&gt;watch&lt;/em&gt; feature which watches for
changes in your files and reloads the web page accordingly.&lt;/p&gt;
&lt;p&gt;Run it with &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;hugo server&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; command.&lt;/p&gt;
&lt;p&gt;Now open &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;http://localhost:1313&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; in your browser. By default, Hugo will not show
anything, because it cannot find any HTML file in the public directory.&lt;/p&gt;
&lt;p&gt;The command to load web server with &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;--watch&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; option is:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; hugo server --watch --verbose
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;...&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;...&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;                   |&lt;/span&gt; EN
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;+------------------+----+&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  Pages&lt;/span&gt;            |  4
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  Paginator&lt;/span&gt; pages  |  0
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  Non-page&lt;/span&gt; files   |  0
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  Static&lt;/span&gt; files     |  0
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  Processed&lt;/span&gt; images |  0
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  Aliases&lt;/span&gt;          |  0
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  Sitemaps&lt;/span&gt;         |  1
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  Cleaned&lt;/span&gt;          |  0
 
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Total&lt;/span&gt; in 11 ms
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;...&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;...&lt;/span&gt;
 &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;update-the-home-page-template&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#update-the-home-page-template&quot;&gt;Update the Home page template&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hugo looks for following directories in theme&apos;s &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/layout&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; folder to search for
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;index.html&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; page.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;index.html&lt;/li&gt;
&lt;li&gt;_default/list.html&lt;/li&gt;
&lt;li&gt;_default/single.html&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is always desirable to update the most specific template related to the
content type. It is not a hard and fast rule, but a good generalization to
follow.&lt;/p&gt;
&lt;p&gt;We will first make a static page to see if our &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;index.html&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; page is rendered
correctly.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;$ vim themes/zeo/layouts/index.html&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;!&lt;/span&gt;DOCTYPE html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;p&gt;Hello World!&amp;#x3C;/p&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;/&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;html&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Build the site and verify the results. You should see &lt;em&gt;Hello World!&lt;/em&gt; when you
open &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;http://localhost:1313&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;h2 id=&quot;building-a-functional-home-page&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#building-a-functional-home-page&quot;&gt;Building a functional Home Page&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now we will create a home page which will reflect the content of our site every
time we build it.&lt;/p&gt;
&lt;p&gt;For that, we will first create some new posts. We will display these posts as a
list on the home page and on their pages, too.&lt;/p&gt;
&lt;p&gt;Hugo has a command for generating skeleton of posts, just like it did for sites
and themes.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; hugo --verbose new post/first.md
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;INFO&lt;/span&gt; 2018/02/11 11:40:58 Using config file: /home/yash/zeo/config.yaml
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;INFO&lt;/span&gt; 2018/02/11 11:40:58 attempting to create &quot;post/first.md&quot; of &quot;post&quot; of ext &quot;.md&quot;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;INFO&lt;/span&gt; 2018/02/11 11:40:58 curpath: /home/yash/zeo/archetypes/default.md
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;...&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;...&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;/home/yash/zeo/content/post/first.md&lt;/span&gt; created&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;new&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; command uses an archetype to generate the frontmatter for new posts.
When we created our site, hugo created a default archetype in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/archetype&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;
folder.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; cat archetypes/default.md
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;---&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;title:&lt;/span&gt; &quot;{{ replace .Name &quot;-&quot; &quot; &quot; | title }}&quot;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;date:&lt;/span&gt; {{ .Date }}
 
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;---&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;It is a good idea to create a default archetype in the themes folder also so
that users can override the theme&apos;s archetype with their archetype whenever they
want.&lt;/p&gt;
&lt;p&gt;We will create a new archetype for our posts&apos; frontmatter and delete the default
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;archetype/default.md&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; rm -rf archetype/default.md
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; vim themes/zeo/archetypes/post.md
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;---&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;title:&lt;/span&gt; &quot;{{ replace .Name &quot;-&quot; &quot; &quot; | title }}&quot;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;date:&lt;/span&gt; {{ .Date }}
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Description:&lt;/span&gt; &quot;&quot;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Tags:&lt;/span&gt; []
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Categories:&lt;/span&gt; []
 
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;---&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Create one more post in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;content/post&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; directory.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; hugo --verbose new post/second.md
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;INFO&lt;/span&gt; 2018/02/11 12:13:56 Using config file: /home/yash/zeo/config.yaml
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;INFO&lt;/span&gt; 2018/02/11 12:13:56 attempting to create &quot;post/second.md&quot; of &quot;post&quot; of ext &quot;.md&quot;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;INFO&lt;/span&gt; 2018/02/11 12:13:56 curpath: /home/yash/zeo/themes/zeo/archetypes/post.md
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;...&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;...&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;/home/yash/zeo/content/post/second.md&lt;/span&gt; created&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;See the difference. Hugo used the theme&apos;s archetype for generating the
frontmatter this time.&lt;/p&gt;
&lt;p&gt;By default, Hugo does not generate posts with an empty content section. So you
will need to add some content before you try to build the site.&lt;/p&gt;
&lt;p&gt;Let&apos;s look at the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;content/post/first.md&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file, after adding content to it.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; cat content/post/first.md
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;---&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;title:&lt;/span&gt; &quot;First&quot;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;date:&lt;/span&gt; 2018-02-11T11:35:58+05:30
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;draft:&lt;/span&gt; true
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Tags:&lt;/span&gt; [&quot;first&quot;]
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Categories:&lt;/span&gt; [&quot;Hugo&quot;]
 
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;---&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Hi&lt;/span&gt; there. My first Hugo post&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now that our posts are ready, we need to create templates to show them in a list
on the home page and to show their content on separate pages for each post.&lt;/p&gt;
&lt;p&gt;We will first edit the template for the home page that we created previously. We
will then modify &quot;single&quot; templates which are used to generate output for a
single content file. We also have &quot;list&quot; templates which are used to group
similar type of content and render them as a list. The home page will show a
list of last ten posts that we have created. Let&apos;s update its template to add
this logic.&lt;/p&gt;
&lt;h2 id=&quot;update-your-home-page-to-show-your-content&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#update-your-home-page-to-show-your-content&quot;&gt;Update your home page to show your content&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now add your template code to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;themes/zeo/layouts/index.html&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;$ vim themes/zeo/layouts/index.html $ cat !$ cat themes/zeo/layouts/index.html&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;!&lt;/span&gt;DOCTYPE html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    {{ range first 10 .Data.Pages }}&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;h1&gt;{{ .Title }}&amp;#x3C;/h1&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    {{ end }}&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;/&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;html&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Hugo uses Go Template Engine. This engine scans the templates for commands that
are enclosed between &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;{{&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;}}&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. In this template, the commands are &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;range&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;,
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;first&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;.Data.Pages&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;.Title&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The template implies that we are going to get first 10 latest pages from our
content folder and render their title as &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;h1&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; heading.&lt;/p&gt;
&lt;p&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;range&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is an iterator function. Hugo treats every HTML file created as a page,
so &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;range&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; will loop through all the pages created. Here we are instructing
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;range&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to stop after first ten pages.&lt;/p&gt;
&lt;p&gt;The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; command signals the end of the &lt;em&gt;range&lt;/em&gt; iterator. The engine loops back
to the next iteration as soon as it encounters the &lt;em&gt;end&lt;/em&gt; command. Everything
between &lt;em&gt;range&lt;/em&gt; and &lt;em&gt;end&lt;/em&gt; will be evaluated for each iteration of the loop.&lt;/p&gt;
&lt;p&gt;Build the website and see the changes. The homepage now shows our two posts.
However, you cannot click on the posts and read their content. Let&apos;s change that
too.&lt;/p&gt;
&lt;h2 id=&quot;linking-your-posts-on-home-page&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#linking-your-posts-on-home-page&quot;&gt;Linking your posts on Home Page&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&apos;s add a link to the post&apos;s page from home page.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;$ vim themes/zeo/layouts/index.html&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;!&lt;/span&gt;DOCTYPE html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    {{ range first 10 .Data.Pages }}&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;h1&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      &amp;#x3C;&lt;/span&gt;a href=&quot;{{ .Permalink }}&quot;&gt;{{ .Title }}&amp;#x3C;/a&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;/&lt;/span&gt;h1&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    {{ end }}&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;/&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;html&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Build your site and see the result. The titles are now links, but when you click
on them, it takes you to a page which says &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;404 page not found&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. That is
expected because we have not created any template for the single pages where the
content can be rendered. So Hugo could not find any template, and it did not
output any HTML file. We will change that in a minute.&lt;/p&gt;
&lt;p&gt;We want to render the posts, which are in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;content/post&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; directory. That means
that their section is post and their type is also post.&lt;/p&gt;
&lt;p&gt;Hugo uses section and type information to identify the template file for each
piece of content. It will first look for a template file which matches the
section or type of the content. If it could not find it, then it will use
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;_default/single.html&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file.&lt;/p&gt;
&lt;p&gt;Since we do not have any other content type yet, we will just start by updating
the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;_default/single.html&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file.&lt;/p&gt;
&lt;p&gt;Remember that Hugo will use this file for every content type for which we have
not created a template. However, for now, we will accept that cost as we do not
have any other content type with us. We will refactor our templates to
accommodate more content types, as we add more content.&lt;/p&gt;
&lt;p&gt;Update the template file.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;$ vim themes/zeo/layouts/_default/single.html&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;!&lt;/span&gt;DOCTYPE html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;head&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;title&gt;{{ .Title }}&amp;#x3C;/title&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;/&lt;/span&gt;head&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;h1&gt;{{ .Title }}&amp;#x3C;/h1&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    {{ .Content }}&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;/&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;html&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Build the site and verify the results. You will see that on clicking on &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;first&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;,
you get the usual result, but clicking on &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;second&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; still produces the
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;404 page not found&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; error. It is because Hugo does not generate pages with
empty content. Remember I mentioned it earlier.&lt;/p&gt;
&lt;p&gt;Now that we have our home page and posts page ready, we will build a page to
list all the posts, not just the recent ten posts. This page will be accessible
at &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;http://localhost:1313/post&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. Currently, this page is blank because there is
no template defined for it.&lt;/p&gt;
&lt;p&gt;This page will show the listings of all the posts, so the type of this page will
be a list. We will again use the default &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;_default/list.html&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; as we do not have
any other content type with us.&lt;/p&gt;
&lt;p&gt;Update the list file.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;$ vim themes/zeo/layouts/_default/list.html&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;!&lt;/span&gt;DOCTYPE html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    {{ range .Data.Pages }}&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;h1&gt;&amp;#x3C;a href=&quot;{{ .Permalink }}&quot;&gt;{{ .Title }}&amp;#x3C;/a&gt;&amp;#x3C;/h1&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    {{ end }}&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;/&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;html&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;add-date-published-to-the-posts&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#add-date-published-to-the-posts&quot;&gt;Add &quot;Date Published&quot; to the posts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is a standard practice to add the date on which the post was published on the
blog. The front matter of our posts has a variable named &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;date&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. We will use
that variable to fetch the date. Our posts are using the default &lt;em&gt;single&lt;/em&gt;
template, so we will edit that file.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;$ vim themes/zeo/layouts/_default/single.html&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;!&lt;/span&gt;DOCTYPE html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;head&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;title&gt;{{ .Title }}&amp;#x3C;/title&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;/&lt;/span&gt;head&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;h1&gt;{{ .Title }}&amp;#x3C;/h1&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;h2&gt;{{ .Date.Format &quot;Sun, Feb 11, 2018&quot; }}&amp;#x3C;/h2&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    {{ .Content }}&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;/&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;html&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;hr&gt;
&lt;h1 id=&quot;adding-top-level-pages&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#adding-top-level-pages&quot;&gt;Adding top-level Pages&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Okay, so now that we have our homepage, post-list page and post content pages in
place, we will add a new &lt;em&gt;about&lt;/em&gt; page at the top level of our blog, not at a
sublevel like we did for posts.&lt;/p&gt;
&lt;p&gt;Hugo uses the directory structure of the content directory to identify the
structure of the blog. Let&apos;s verify that and create a new &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;about&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; page in the
content directory.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;$ vim content/about.md&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;---&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;title&lt;/span&gt;: &quot;about&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;description&lt;/span&gt;: &quot;about this blog&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;date&lt;/span&gt;: &quot;2018-02-11&quot;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#6F42C1&quot;&gt;---&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;### about me&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;Hi there, you just reached my blog.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Let&apos;s generate the site and view the results.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; hugo --verbose
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;$&lt;/span&gt; ls -l public/
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;total&lt;/span&gt; 36
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;drwxr-xr-x&lt;/span&gt; 2 yash hogwarts 4096 Feb 11 12:43 about
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;drwxr-xr-x&lt;/span&gt; 3 yash hogwarts 4096 Feb 11 12:43 categories
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;drwxr-xr-x&lt;/span&gt; 2 yash hogwarts 4096 Feb 11 11:20 css
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;-rw-r--r--&lt;/span&gt; 1 yash hogwarts  187 Feb 11 12:43 index.html
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;-rw-r--r--&lt;/span&gt; 1 yash hogwarts 1183 Feb 11 12:43 index.xml
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;drwxr-xr-x&lt;/span&gt; 2 yash hogwarts 4096 Feb 11 11:20 js
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;drwxr-xr-x&lt;/span&gt; 4 yash hogwarts 4096 Feb 11 12:43 post
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;-rw-r--r--&lt;/span&gt; 1 yash hogwarts 1139 Feb 11 12:43 sitemap.xml
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;drwxr-xr-x&lt;/span&gt; 3 yash hogwarts 4096 Feb 11 12:43 tags&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Notice that Hugo created a new directory &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;about&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. This directory contains only
one file &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;index.html&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. The about page will be rendered from &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;about/index.html&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;If you look carefully, the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;about&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; page is listed with the posts on the
homepage. It is not desirable, so let&apos;s change that first.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;$ vim themes/zeo/layouts/index.html&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;!&lt;/span&gt;DOCTYPE html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;h1&gt;posts&amp;#x3C;/h1&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    {{ range first 10 .Data.Pages }} {{ if eq .Type &quot;post&quot;}}&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;h2&gt;&amp;#x3C;a href=&quot;{{ .Permalink }}&quot;&gt;{{ .Title }}&amp;#x3C;/a&gt;&amp;#x3C;/h2&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    {{ end }} {{ end }}&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;h1&gt;pages&amp;#x3C;/h1&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    {{ range .Data.Pages }} {{ if eq .Type &quot;page&quot; }}&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;h2&gt;&amp;#x3C;a href=&quot;{{ .Permalink }}&quot;&gt;{{ .Title }}&amp;#x3C;/a&gt;&amp;#x3C;/h2&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    {{ end }} {{ end }}&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;/&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;html&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now build the site and verify the results. The homepage now has two sections,
one for posts and other for the pages. Click on the &lt;em&gt;about&lt;/em&gt; page. You will see
the page for &lt;em&gt;about&lt;/em&gt;. Remember, I mentioned that Hugo would use the &lt;em&gt;single&lt;/em&gt;
template for each page, for which it cannot find a template file. There is still
one issue. The &lt;em&gt;about&lt;/em&gt; page shows the date also. We do not want to show the date
on the &lt;em&gt;about&lt;/em&gt; page.&lt;/p&gt;
&lt;p&gt;There are a couple of ways to fix this. We can add an if-else statement to
detect the type of the content and display date only if it is a post. However,
let&apos;s use the feature provided by Hugo and create a new template type for the
posts. Before we do that, let&apos;s learn to use one more template type which is
&lt;em&gt;partials&lt;/em&gt;.&lt;/p&gt;
&lt;h1 id=&quot;partials-1&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#partials-1&quot;&gt;Partials&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;In Hugo, partials are used to store the shared piece of code which repeats in
more than one templates. Partials are kept in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;themes/zeo/layouts/partials&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;
directory. Partials can be used to override the themes presentation. End users
can use them to change the default behavior of a theme. It is always a good idea
to use partials as much as possible.&lt;/p&gt;
&lt;h2 id=&quot;header-and-footer-partials&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#header-and-footer-partials&quot;&gt;Header and Footer partials&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Header and footer of most of the posts and pages will follow a similar pattern.
So they form an excellent example to be defined as a partial.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;$ vim themes/zeo/layouts/partials/header.html&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;!&lt;/span&gt;DOCTYPE html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;head&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;title&gt;{{ .Title }}&amp;#x3C;/title&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;/&lt;/span&gt;head&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    $ vim themes/zeo/layouts/partials/footer.html&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;/&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;html&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;We can call a partial by including this path in the template&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;go&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;go&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;{{ partial &lt;/span&gt;&quot;header.html&quot; . }}&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;update-the-homepage-template&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#update-the-homepage-template&quot;&gt;Update the Homepage template&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Let&apos;s update our homepage template to use these partials.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;$ vim themes/zeo/layouts/index.html {{ partial &quot;header.html&quot; . }}&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;h1&gt;posts&amp;#x3C;/h1&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;{{ range first 10 .Data.Pages }} {{ if eq .Type &quot;post&quot;}}&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;h2&gt;&amp;#x3C;a href=&quot;{{ .Permalink }}&quot;&gt;{{ .Title }}&amp;#x3C;/a&gt;&amp;#x3C;/h2&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;{{ end }} {{ end }}&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;h1&gt;pages&amp;#x3C;/h1&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;{{ range .Data.Pages }} {{ if or (eq .Type &quot;page&quot;) (eq .Type &quot;about&quot;) }}&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;h2&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;a href=&quot;{{ .Permalink }}&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &gt;{{ .Type }} - {{ .Title }} - {{ .RelPermalink }}&amp;#x3C;/&lt;/span&gt;a
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &gt;&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;h2&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;{{ end }} {{ end }} {{ partial &quot;footer.html&quot; . }}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;update-the-single-template&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#update-the-single-template&quot;&gt;Update the single template&lt;/a&gt;&lt;/h1&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;$ vim themes/zeo/layouts/_default/single.html {{ partial &quot;header.html&quot; . }}&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;h1&gt;{{ .Title }}&amp;#x3C;/h1&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;h2&gt;{{ .Date.Format &quot;Sun, Feb 11, 2018&quot; }}&amp;#x3C;/h2&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;{{ .Content }} {{ partial &quot;footer.html&quot; . }}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Build the website and verify the results. The title on the posts and the about
page should both reflect the value from the markdown file.&lt;/p&gt;
&lt;h1 id=&quot;fixing-the-date-shown-on-about-page&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#fixing-the-date-shown-on-about-page&quot;&gt;Fixing the date shown on About page&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Remember, we had the issue that the date was showing on the &lt;em&gt;about&lt;/em&gt; page also.
We discussed one method to solve this issue. Now I will discuss a more &lt;em&gt;hugoic&lt;/em&gt;
way of solving this issue.&lt;/p&gt;
&lt;p&gt;We will create a new section template to fix this issue.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;html&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;$ mkdir themes/zeo/layouts/post $ vim themes/zeo/layouts/post/single.html {{&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;partial &quot;header.html&quot; . }}&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;h1&gt;{{ .Title }}&amp;#x3C;/h1&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;h2&gt;{{ .Date.Format &quot;Mon, Jan 2, 2006&quot; }}&amp;#x3C;/h2&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;{{ .Content }} {{ partial &quot;footer.html&quot; . }} $ vim&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;themes/zeo/layouts/_default/single.html&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;!&lt;/span&gt;DOCTYPE html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;html&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;head&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;title&gt;{{ .Title }}&amp;#x3C;/title&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;/&lt;/span&gt;head&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;h1&gt;{{ .Title }}&amp;#x3C;/h1&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    {{ .Content }}&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  &amp;#x3C;/&lt;/span&gt;body&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;html&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Note that we have changed the default &lt;em&gt;single&lt;/em&gt; template and added that logic in
post&apos;s &lt;em&gt;single&lt;/em&gt; template.&lt;/p&gt;
&lt;p&gt;Build the website and verify the results. The &lt;em&gt;about&lt;/em&gt; page does not show the
date now, but the posts page still show the date. We can also move the list
template&apos;s logic to the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;index.html&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file of post section template.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We have learnt, how Hugo harnesses the powerful yet simple Go template engine to
create the static site generator. We also learnt about partials and their
excellent utilization by Hugo in the spirit of &lt;em&gt;Don&apos;t Repeat Yourself&lt;/em&gt;
principle. Now that you know how to make themes in Hugo, go ahead and start
creating new beautiful themes. Best of luck for your endaevour.&lt;/p&gt;</content:encoded></item><item><title>My New Domain</title><link>https://yashagarwal.in/notes/my-new-domain/</link><guid isPermaLink="true">https://yashagarwal.in/notes/my-new-domain/</guid><description>Announcing a new personal domain and plans to automate SSL certificate deployment using GitLab and GoDaddy APIs for seamless website management.</description><pubDate>Sun, 25 Feb 2018 04:40:04 GMT</pubDate><content:encoded>&lt;p&gt;I bought a new domain a few days back - &lt;em&gt;yashagarwal.in&lt;/em&gt;. I was trying to buy
this domain for the last two years, but it was already taken. My previous
domain, &lt;em&gt;yashagarwal.me&lt;/em&gt; that I got for free via GitHub education pack, was good
enough for me, but the thought that I own a domain which is a top-level domain
of some other country was in itself something which was not comfortable to me.
So when I got the chance to buy this domain, I didn&apos;t delay. Hope this domain
will remain my personal home on the web for years to come.&lt;/p&gt;
&lt;p&gt;The domain is mapped with GitLab, and the SSL certificates are provided by
&lt;a href=&quot;https://letsencrypt.org/&quot;&gt;Let&apos;s Encrypt&lt;/a&gt;. Let&apos;s Encrypt requires you to renew
the SSL certificates every 90 days. That seems like a manual work to me.
Moreover, my new registrar, GoDaddy, provides a complete API for their domain
services. So I am planning to write a script that utilizes the APIs of
&lt;a href=&quot;https://gitlab.com/help/api/README.md&quot;&gt;GitLab&lt;/a&gt; and
&lt;a href=&quot;https://developer.godaddy.com/&quot;&gt;GoDaddy&lt;/a&gt; to deploy the SSL certificates
automatically. I will probably use the DNS based authentication to verify the
ownership of my domain, as that seems the only method that does not require any
modification on the host side. I will write a post with all the details about
the script, once I finish implementing it.&lt;/p&gt;
&lt;p&gt;That&apos;s all for this post. See you next time. :)&lt;/p&gt;</content:encoded></item><item><title>Syncing Time on Windows &amp; GNU/Linux Dual Boot Setups</title><link>https://yashagarwal.in/notes/syncing-time-on-windows-gnu-linux-dual-boot-setups/</link><guid isPermaLink="true">https://yashagarwal.in/notes/syncing-time-on-windows-gnu-linux-dual-boot-setups/</guid><description>Resolve time synchronization issues in Windows and Linux dual-boot setups. Learn how to configure your system to use UTC for seamless time management.</description><pubDate>Thu, 01 Feb 2018 07:24:34 GMT</pubDate><content:encoded>&lt;p&gt;This post is going to be one of those that I have written for my reference.
Whatever I am going to mention in this post is not new. Everything has already
been said and written many times on many websites and Linux forums.&lt;/p&gt;
&lt;p&gt;So I will start by explaining the problem. When you try to dual boot your
machine to run both GNU/Linux and Windows operating systems, you might have
noticed that the time is not the same in both the operating systems. It is
generally one operating system showing the correct time, and the other one
showing the wrong time. It happens because Microsoft Windows thinks that the
hardware clock (CMOS clock or BIOS clock) of the machine is using the local time
(depends on your current time zone), and hence it doesn&apos;t do anything and shows
you the same time. But most GNU/Linux operating systems (Ubuntu, Arch Linux,
etc.) think that the hardware clock is set to track UTC. Hence the mismatch in
the time happens. For example, assume that the current real-time is 10:22:51,
and the hardware clock time is set to 10:22:51. Windows will interpret this time
as local time and show 10:22:51, but Linux based systems will show 15:52:51
because they will understand this time as UTC. Of course, the above example is
true if we assume time zone as India, which is +05:30 from UTC.&lt;/p&gt;
&lt;p&gt;This issue can be fixed either from Windows or from GNU/Linux OS. I prefer to
adjust the behavior of Windows to use UTC. It is much more convenient to use
when traveling between different time zones. Please note that this method might
not work or cause instability with older versions of Windows OS. I have tried
this fix on Windows 10, and it works without any issues.&lt;/p&gt;
&lt;p&gt;Open an Administrator Command Prompt by pressing &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;⊞ + x&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, then type &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;a&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. This
method of opening the Administrator Command Prompt does not work on Windows 7.&lt;/p&gt;
&lt;p&gt;Now execute the following command:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;reg&lt;/span&gt; add &quot;HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\TimeZoneInformation&quot; /v RealTimeIsUniversal /d 1 /t REG_DWORD /f&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Windows Time Service, which keeps the clock in Windows OS accurate, will still
write the local time to the Real-time clock (RTC) regardless of the registry
settings on shutdown. So I prefer to disable the Windows Time Service.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sc&lt;/span&gt; config w32time start= disabled&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now you may need to change the time in your BIOS to UTC time, although that
depends on whether your Windows OS was showing the correct time before applying
the above modifications. If yes, then changing BIOS time to UTC will make sure
that both Windows and GNU/Linux convert hardware clock to local time.&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id=&quot;references&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#references&quot;&gt;References&lt;/a&gt;&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://help.ubuntu.com/community/UbuntuTime#Multiple_Boot_Systems_Time_Conflicts&quot;&gt;Multiple Boot Systems Time Conflicts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.archlinux.org/index.php/Time#UTC_in_Windows&quot;&gt;UTC in Windows&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</content:encoded></item><item><title>Why a Sanskrit Shloka?</title><link>https://yashagarwal.in/notes/why-a-sanskrit-shloka/</link><guid isPermaLink="true">https://yashagarwal.in/notes/why-a-sanskrit-shloka/</guid><description>Discover the personal significance of a Sanskrit shloka on my blog, reflecting on college experiences and life lessons learned.</description><pubDate>Tue, 30 Jan 2018 14:59:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;श्रूयतां धर्मसर्वस्वं श्रुत्वा चैवावधार्यताम्। &lt;br&gt;
आत्मनः प्रतिकूलानि परेषां न समाचरेत्॥&lt;/p&gt;
&lt;p&gt;If the entire Dharma can be said in a few words, then it is - that which is
unfavorable to us, do not do that to others.&lt;br&gt;&lt;/p&gt;
&lt;p&gt;— Padmapuraana, shrushti 19/357-358&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So when you landed on this blog, the first thing you might have noticed is that
the home page of this blog has a Sanskrit shloka. Many people ask me, why did I
choose to display a Sanskrit shloka on my blog.&lt;/p&gt;
&lt;p&gt;There is no one answer to this question. There have been several incidents in my
undergraduate life, which have given me a lot of good and evil memories. This
shloka summarizes all those experiences that I earned in NIT Calicut during my
undergraduate course. It reminds me, how I should treat others to receive
similar treatment.&lt;/p&gt;
&lt;p&gt;It was my first time away from home and family when I got admission in NIT
Calicut. I was very naive about judging people. I got to know many new people in
NITC. That is when I learned that not everyone is helping you. People are here
to exploit you, and they will do anything to achieve their goals and to get
success, whether it comes at the price of someone else&apos;s loss. It is the harsh
truth of life, and the sooner one understands this, the better. I realized this
in my second year, and that is when my life changed. Thankfully, I did not find
other such people after my first year. However, life is very long, and I am
bound to find such people at some point in my life again. I hope the experience
that I earned in NITC will help me face that time.&lt;/p&gt;
&lt;p&gt;Now, to the second part of the question, why Sanskrit? A quick Google search
reveals that this shloka represents the concept of
&lt;a href=&quot;https://en.wikipedia.org/wiki/Golden_Rule&quot;&gt;Golden Rule&lt;/a&gt;, which is common to
most world religions, and Hinduism is no exception here. There is even a
&lt;a href=&quot;https://hinduism.stackexchange.com/questions/21431/what-all-hindu-scriptures-advocate-the-golden-rule-and-what-is-the-oldest-hindu&quot;&gt;question&lt;/a&gt;
about the relation of this shloka with Hinduism. I studied Sanskrit for six
years till my 10&lt;sup&gt;th&lt;/sup&gt; standard and feel a connection to it. Besides,
Hindi is my mother tongue, so Sanskrit was the obvious choice given that there
is not much Hinduism related literature available in Hindi.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edit(23/03/2018)&lt;/strong&gt;: I have removed the shloka from the front page now. I am
keeping this post for historical purpose.&lt;/p&gt;</content:encoded></item><item><title>Arch Linux Installation Guide Part 2</title><link>https://yashagarwal.in/notes/arch-linux-installation-guide-part-2/</link><guid isPermaLink="true">https://yashagarwal.in/notes/arch-linux-installation-guide-part-2/</guid><description>Guide to setting up Arch Linux for daily use, including installing essential apps, X server, and a full LAMP stack for development.</description><pubDate>Fri, 26 Jan 2018 10:15:27 GMT</pubDate><content:encoded>&lt;p&gt;In this post, I will continue from my last
&lt;a href=&quot;https://yashagarwal.in/notes/arch-linux-installation-guide-part-1/&quot;&gt;post&lt;/a&gt; and set up my newly installed Arch
Linux for daily use. I am going to install some applications that I use on a day
to day basis. Some of these applications are required for my current dotfile
&lt;a href=&quot;https://yashagarwal.in/notes/my-own-configuration-manager/&quot;&gt;configuration&lt;/a&gt; setup to work properly. The
choice of applications is highly opinionated and your preferences might be
different.&lt;/p&gt;
&lt;p&gt;If you had gone for installation via SSH option, then I would suggest you to
edit your &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sshd_config&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file and disable &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;root&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; login. It can be a security risk
otherwise.&lt;/p&gt;
&lt;h1 id=&quot;install-a-terminal-based-browser&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#install-a-terminal-based-browser&quot;&gt;Install a terminal based browser&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Terminal-based browsers are very handy in cases when you are required to login
into a captive portal and you don&apos;t have access to a graphical browser. We will
install two different browsers, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;elinks&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;w3m&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; pacman -S elinks w3m&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;install-x-server&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#install-x-server&quot;&gt;Install X server.&lt;/a&gt;&lt;/h1&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; pacman -S xorg&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This will install minimal X desktop environment with fonts, in case, you want to
test your system before installing any desktop environment.&lt;/p&gt;
&lt;h1 id=&quot;enable-multilib-repository-for-32-bit-package-support&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#enable-multilib-repository-for-32-bit-package-support&quot;&gt;Enable multilib repository for 32-bit package support&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;To enable multilib repository, uncomment the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;[multilib]&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; section in
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/pacman.conf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;[multilib]&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Include&lt;/span&gt; = /etc/pacman.d/mirrorlist&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now upgrade your system.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; pacman -Syyu&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;install-video-and-touchpad-drivers&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#install-video-and-touchpad-drivers&quot;&gt;Install video and touchpad drivers&lt;/a&gt;&lt;/h1&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; pacman -S xf86-video-intel xf86-input-synaptics&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;install-pacaur-to-fetch-and-install-packages-from-aur&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#install-pacaur-to-fetch-and-install-packages-from-aur&quot;&gt;Install pacaur to fetch and install packages from AUR&lt;/a&gt;&lt;/h1&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; pacman -S expac yajl --noconfirm
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;cd&lt;/span&gt; /tmp
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;gpg&lt;/span&gt; --recv-keys --keyserver hkp://pgp.mit.edu:80 1EB2638FF56C0C53
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;curl&lt;/span&gt; -o PKGBUILD https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=cower
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;makepkg&lt;/span&gt; -i PKGBUILD --noconfirm
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;curl&lt;/span&gt; -o PKGBUILD https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=pacaur
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;makepkg&lt;/span&gt; -i PKGBUILD --noconfirm
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;cd&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;install-graphical-browsers&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#install-graphical-browsers&quot;&gt;Install graphical browsers&lt;/a&gt;&lt;/h1&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;pacaur&lt;/span&gt; -S firefox chromium&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;install-code-editors&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#install-code-editors&quot;&gt;Install code editors&lt;/a&gt;&lt;/h1&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;pacaur&lt;/span&gt; -S sublime-text-dev atom-editor-git visual-studio-code-bin neovim neovim-drop-in leafpad&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;setup-lamp-stack&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#setup-lamp-stack&quot;&gt;Setup LAMP stack&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&quot;install-apache-server&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#install-apache-server&quot;&gt;Install Apache server&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; pacman -S apache
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Make your user-directory available to apache server&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;mkdir&lt;/span&gt; ~/public_html
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;chmod&lt;/span&gt; o+x ~
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;chmod&lt;/span&gt; o+x ~/public_html
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;chmod&lt;/span&gt; -R o+r ~/public_html&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# To enable virtualhosts, uncomment the following line in `/etc/httpd/conf/httpd.conf`&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Include&lt;/span&gt; conf/extra/httpd-vhosts.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Add your virtualhost configuration in following file -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; vim /etc/httpd/conf/extra/httpd-vhosts.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;To test the virtual hosts on you local machine, add the virtual names to your
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/hosts&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file.&lt;/p&gt;
&lt;h2 id=&quot;install-php&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#install-php&quot;&gt;Install PHP&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; pacman -S php php-apache&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;To use PHP with apache, open &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/httpd/conf/httpd.conf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and uncomment
following line -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;LoadModule&lt;/span&gt; mpm_prefork_module modules/mod_mpm_prefork.so&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;and comment out the following line -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# LoadModule mpm_event_module modules/mod_mpm_event.so&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now add these lines to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/httpd/conf/httpd.conf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Add these at the end of `LoadModule` section.&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;LoadModule&lt;/span&gt; php7_module modules/libphp7.so
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;AddHandler&lt;/span&gt; php7-script .php
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Place this at the end of the `Include` section:&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Include&lt;/span&gt; conf/extra/php7_module.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;install-mysql-server&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#install-mysql-server&quot;&gt;Install MySQL server&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; pacman -S mariadb
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Initialize the MariaDB data directory prior to starting the service. To do so, run:&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; mysql_install_db --user=mysql --basedir=/usr --datadir=/var/lib/mysql
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# Then issue the commands to start the database server&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; systemctl enable mariadb.service
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; systemctl start mariadb.service
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# To apply recommended security settings to your database, run&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; mysql_secure_installation&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;install-phpmyadmin&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#install-phpmyadmin&quot;&gt;Install PHPMyAdmin&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; pacman -S phpmyadmin php-mcrypt&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Enable &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;mysqli&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;mcrypt&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;zip&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;bz2&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; extensions in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/php/php.ini&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Create the apache configuration file &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/httpd/conf/extra/phpmyadmin.conf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;apache&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;apache&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;Alias&lt;/span&gt; /phpmyadmin &quot;/usr/share/webapps/phpMyAdmin&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;Directory &quot;/usr/share/webapps/phpMyAdmin&quot;&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    DirectoryIndex&lt;/span&gt; index.php
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    AllowOverride&lt;/span&gt; All
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    Options&lt;/span&gt; FollowSymlinks
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    Require&lt;/span&gt; all granted
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;Directory&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Then include following in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/httpd/conf/httpd.conf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;apache&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;apache&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# phpMyAdmin configuration&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;Include&lt;/span&gt; conf/extra/phpmyadmin.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now restart &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;httpd&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; service to apply settings.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; systemctl restart httpd&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Once all these steps are done, your LAMP stack should be working.&lt;/p&gt;
&lt;h1 id=&quot;setup-power-management&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#setup-power-management&quot;&gt;Setup power management&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Install &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;tlp&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and some of its optional dependencies&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; pacman -S tlp tlp-rdw bash-completion ethtool lsb-release smartmontools&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Then enable &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;tlp&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; services&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; systemctl enable tlp.service
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; systemctl enable tlp-sleep.service
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# mask some services for tlp to work properly&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; systemctl mask systemd-rfkill.service
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; systemctl mask systemd-rfkill.socket&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;install-i3-and-other-tools&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#install-i3-and-other-tools&quot;&gt;Install i3 and other tools&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;All these tools are part of my &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;i3&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; config with exception of the theme related
packages. So installing them here will help me later while setting up the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;i3&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;
window manager.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;pacaur&lt;/span&gt; -S i3 rofi polybar xautolock powerline-fonts-git i3lock-fancy-git compton scrot feh dunst unclutter xfce4-power-manager numlockx lxappearance adapta-gtk-theme gtk-engine-murrine gnome-themes-standard termite&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;fix-ugly-fonts-1&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#fix-ugly-fonts-1&quot;&gt;Fix Ugly Fonts &lt;sup&gt;&lt;/sup&gt;&lt;/a&gt;&lt;a href=&quot;https://yashagarwal.in/#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Fonts rendering is one area where Linux still lags behind Windows and OSX. It
can be a nightmare for users to setup fonts properly in Linux. In Arch Linux,
this is even worse. I found some tricks to improve the quality of font rendering
on Arch Linux. Though this is far from perfect, it is manageable. Follow these
&lt;a href=&quot;https://www.reddit.com/r/archlinux/comments/5r5ep8/make_your_arch_fonts_beautiful_easily/&quot;&gt;steps&lt;/a&gt;
on Reddit to fix font rendering. I use Noto Sans, Adobe Source Code Pro, and
Microsoft fonts. My apologies, but I can&apos;t help here. Some websites still use
Microsoft fonts.&lt;/p&gt;
&lt;h1 id=&quot;setup-python-environment&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#setup-python-environment&quot;&gt;Setup Python Environment&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I use Python extensively and virtual environments are a must for my development
setup. I use &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pipenv&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to manage my virtual environments. To install &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pipenv&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;,
you need to install &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;virtualenv&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; first. To install it, run the following
command.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; pacman -S python-virtualenv&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now you are ready to install &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pipenv&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. Follow
&lt;a href=&quot;https://pipenv.pypa.io/en/latest/&quot;&gt;here&lt;/a&gt; to install the tool.&lt;/p&gt;
&lt;h1 id=&quot;install-some-other-common-tools&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#install-some-other-common-tools&quot;&gt;Install some other common tools&lt;/a&gt;&lt;/h1&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; pacman -S vlc openssh npm imagemagick git la-capitaine-icon-theme-git&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Do not forget to
&lt;a href=&quot;https://stackoverflow.com/questions/10081293/install-npm-into-home-directory-with-distribution-nodejs-package-ubuntu/13021677#13021677&quot;&gt;setup&lt;/a&gt;
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to install packages globally without requiring &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;That&apos;s all! Your system should be in working condition now. Do check out my
&lt;a href=&quot;https://yashagarwal.in/notes/my-own-configuration-manager/&quot;&gt;dotfiles&lt;/a&gt; if you want to set up your
system like mine.&lt;/p&gt;
&lt;p&gt;Hope you enjoyed the article. Cheers 😄&lt;/p&gt;
&lt;section data-footnotes=&quot;&quot;&gt;&lt;h2 id=&quot;footnote-label&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#footnote-label&quot;&gt;Footnotes&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://www.reddit.com/r/archlinux/comments/5r5ep8/make_your_arch_fonts_beautiful_easily/&quot;&gt;Make your Arch fonts beautiful easily!&lt;/a&gt; &lt;a href=&quot;https://yashagarwal.in/#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded></item><item><title>Arch Linux Installation Guide Part 1</title><link>https://yashagarwal.in/notes/arch-linux-installation-guide-part-1/</link><guid isPermaLink="true">https://yashagarwal.in/notes/arch-linux-installation-guide-part-1/</guid><description>A comprehensive guide to installing Arch Linux from scratch, covering network setup, disk partitioning, and base system installation.</description><pubDate>Wed, 24 Jan 2018 16:19:05 GMT</pubDate><content:encoded>&lt;p&gt;Arch Linux is a Linux distribution known for its not-so-beginner-friendly
command line installer, no ready-to-use system after installation and
requirement of above average knowledge of command line. However, Arch Linux
allows me to set up a system in my desired state in shortest possible time with
least effort. This is why I keep coming back to Arch Linux even after some of
its annoyances.&lt;/p&gt;
&lt;p&gt;This guide is written primarily for my reference, as someone who has installed
Arch Linux several times, I still can&apos;t remember all the installation steps
perfectly. Most of the steps have been taken from
&lt;a href=&quot;https://wiki.archlinux.org/index.php/installation_guide&quot;&gt;Arch wiki&lt;/a&gt; and should
work on other setups also.&lt;/p&gt;
&lt;p&gt;All the commands are run in root shell unless otherwise specified.&lt;/p&gt;
&lt;h1 id=&quot;0-check-your-network-connection&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#0-check-your-network-connection&quot;&gt;0. Check your network connection&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;If you are behind a captive portal, use &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;links&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to open browser and login into
your network. For WiFi connections, use &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;wifi-menu&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. LAN connections should not
require any setup. The boot environment should automatically detect any wired
connections. After connecting, test your connection by pinging any website:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;ping&lt;/span&gt; -c 5 google.com&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;1-setup-ssh&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#1-setup-ssh&quot;&gt;1. Setup SSH&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This step is not mandatory, though I prefer to use this method to install Arch
Linux, as it provides me the convenience of copying and pasting the commands
directly from Arch wiki.&lt;/p&gt;
&lt;p&gt;By default the Arch Linux &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;root&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; account password is empty. We need to set up a
password for &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;root&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; account, which is needed for an SSH connection.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;passwd&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now we need to change the setting to permit &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;root&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; login via SSH in
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/ssh/sshd_config&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. Check that &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;PermitRootLogin yes&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is uncommented in this
file. If this line is not present there, add this to the end. Now start the
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sshd.service&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; by issuing the command&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; systemctl start sshd.service&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Also, note the IP address of the target machine by inspecting the output of the
following command.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;ip&lt;/span&gt; addr&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;Pro tip:&lt;/em&gt; One liner to get only the IP address&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;ip&lt;/span&gt; -o -4 addr show | awk -F &apos;[ /]+&apos; &apos;/global/ {print $4}&apos;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now on your host machine, connect to the target machine via SSH using the
following command&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;ssh&lt;/span&gt; root@ip-address-of-target&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;2-partition-the-disks&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#2-partition-the-disks&quot;&gt;2. Partition the disks&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;If Windows 8 or above is already installed on your machine, then your hard disk
is probably using &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;GPT&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; partitioning scheme. In that case, use &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;gdisk&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to
partition your hard disk. &lt;del&gt;If you use &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;fdisk&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; on a GPT partitioned HDD, there
is a possibility of data loss.&lt;/del&gt; &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;fdisk&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; understands &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;GPT&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; partitioning scheme
also.[1]&lt;/p&gt;
&lt;p&gt;My preferred setup is to have one root partition and one home partition and use
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;EFI&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; partition created by Windows to install boot-loader. The root and home
partition will be formatted using &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;ext4&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file-system and the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;EFI&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; partition
should be formatted using &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;FAT32&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file-system.&lt;/p&gt;
&lt;p&gt;For this guide, I am assuming that the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;EFI&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; partition is &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sda1&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, root partition
is &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sda9&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and home partition is &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sda10&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Now to format the partitions with &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;ext4&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file-system:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;mkfs.ext4&lt;/span&gt; /dev/sda9
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;mkfs.ext4&lt;/span&gt; /dev/sda10&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;3-mount-the-partitions&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#3-mount-the-partitions&quot;&gt;3. Mount the partitions&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Now mount the root partition (&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sda9&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; in this case) to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/mnt&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;mount&lt;/span&gt; /dev/sda9 /mnt&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;If you have created any other partitions in previous steps, mount them at
appropriate locations.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;mkdir&lt;/span&gt; /mnt/home
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;mount&lt;/span&gt; /dev/sda10 /mnt/home
 
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;mkdir&lt;/span&gt; /mnt/boot
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;mount&lt;/span&gt; /dev/sda1 /mnt/boot&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;4-install-the-base-file-system&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#4-install-the-base-file-system&quot;&gt;4. Install the base file-system&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;To install the base system and some development tools, issue the following
command.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;pacstrap&lt;/span&gt; /mnt base base-devel&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This will take a while to download and install. After it finishes, it will give
you a bare-bone Arch Linux system with just the tools required to run a Linux
distribution, no other software is installed.&lt;/p&gt;
&lt;h1 id=&quot;5-generate-etcfstab&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#5-generate-etcfstab&quot;&gt;5. Generate /etc/fstab&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/fstab&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file stores the information about file systems of partitions
and how to mount the partitions on system boot up. To generate this file, issue
the following command:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;genfstab&lt;/span&gt; -U /mnt &gt;&gt; /mnt/etc/fstab&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;If you prefer to use partition labels (sda1, sda9 etc.) instead of UUID, then
use &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;-L&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; flag in place of &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;-U&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;h1 id=&quot;6-chroot-into-the-system&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#6-chroot-into-the-system&quot;&gt;6. chroot into the system&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;From the &lt;a href=&quot;https://wiki.archlinux.org/index.php/Change_root&quot;&gt;Arch wiki&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Chroot is an operation that changes the apparent root directory for the
current running process and their children. A program that is run in such a
modified environment cannot access files and commands outside that
environmental directory tree. This modified environment is called a chroot
jail.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;At this step, we will go to the root of the newly installed system at &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/mnt&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and
pretend as if we are logged into this system.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;arch-chroot&lt;/span&gt; /mnt&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;7-setup-the-time-zone-locale-and-hostname&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#7-setup-the-time-zone-locale-and-hostname&quot;&gt;7. Setup the time zone, locale, and hostname&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Browse the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/use/share/zoneinfo&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; directory to find your location entries. My
location is India, so I will use this command.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;ln&lt;/span&gt; -sf /usr/share/zoneinfo/Asia/Kolkata /etc/localtime&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;To set the hardware clock:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;hwclock&lt;/span&gt; --systohc&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;To set the locale for your system, open the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/locale.gen&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file and uncomment
your language. or run the following command for the default &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;en_US.UTF-8 UTF-8&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;LANG&lt;/span&gt;=C perl -i -pe &apos;s/#(en_US.UTF)/$1/&apos; /etc/locale.gen&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now generate the localization with&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;locale-gen&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Then set the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;LANG&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; variable in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/locale.conf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; accordingly, or run the
following command:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;localectl&lt;/span&gt; set-locale LANG=&quot;en_US.UTF-8&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;To set the hostname for your machine:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;hostnamectl&lt;/span&gt; set-hostname your-host-name&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;To allow other machines to address the host by name, it is necessary to edit the
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/hosts&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file to look like this:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;127.0.0.1&lt;/span&gt;    localhost.localdomain          localhost
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;:&lt;/span&gt;:1          localhost.localdomain          localhost
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;127.0.1.1&lt;/span&gt;    your-host-name.localdomain     your-host-name&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;8-create-user-account&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#8-create-user-account&quot;&gt;8. Create user account&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Before creating user account, set password for &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;root&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; account&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;passwd&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now create a local account for your user&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;useradd&lt;/span&gt; -m -G wheel -s /bin/bash your-user-name&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This will set up your user account, create a home directory for your user, set
the default shell to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;bash&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and add your user to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;wheel&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; group, which is
necessary to gain &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; access in later steps.&lt;/p&gt;
&lt;p&gt;Set password for your user.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;passwd&lt;/span&gt; your-user-name&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;9-enable-sudo-access&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#9-enable-sudo-access&quot;&gt;9. Enable sudo access&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This allows you to use root privileges without using the root account. To enable
this, first open &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/sudoers&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;nano&lt;/span&gt; /etc/sudoers&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now uncomment the following line to enable &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;root&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; privilege for all the users
inside &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;wheel&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; group:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# %wheel ALL=(ALL) ALL&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now you can safely disable root account&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;passwd&lt;/span&gt; -l root
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# login into your user account&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;su&lt;/span&gt; your-user-name&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;From this point onwards, it is necessary to append &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to any command that
requires &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;root&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; privileges.&lt;/p&gt;
&lt;h1 id=&quot;10-install-bootloader&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#10-install-bootloader&quot;&gt;10. Install bootloader&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;My preferred bootloader of choice is &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;grub&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. To install &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;grub&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, we need to
install following packages.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; pacman -S grub efibootmgr&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now install &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;grub&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; with the following command.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=arch&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Here &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;--efi-directory&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is the folder where the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;EFI&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; partition is mounted
&lt;a href=&quot;https://yashagarwal.in/#step3&quot;&gt;step 3&lt;/a&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;--bootloader-id&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is the label that will appear in your
UEFI boot menu entry.&lt;/p&gt;
&lt;p&gt;This particular step is specific to my machine&apos;s hardware, you might not need to
run this step. I need to add &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pci=nommconf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to my kernel boot parameters in
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/default/grub&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, otherwise &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;tty&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; prints error messages continuously.&lt;/p&gt;
&lt;p&gt;Now run to generate grub configuration file.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; grub-mkconfig -o /boot/grub/grub.cfg&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;If you encounter any errors related to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;lvm&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; during installation of grub, then
follow these steps.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# come out of chroot&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;exit&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;mkdir&lt;/span&gt; /mnt/hostrun
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;mount&lt;/span&gt; --bind /run /mnt/hostrun
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# back to chroot&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;arch-chroot&lt;/span&gt; /mnt
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;mkdir&lt;/span&gt; /run/lvm
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;mount&lt;/span&gt; --bind /hostrun/lvm /run/lvm&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now you can install &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;grub&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; without any errors.&lt;/p&gt;
&lt;h1 id=&quot;11-configure-the-network&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#11-configure-the-network&quot;&gt;11. Configure the network&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;By default, your current system cannot connect to the network in the current
state. I prefer to use
&lt;a href=&quot;https://wiki.archlinux.org/index.php/NetworkManager&quot;&gt;NetworkManager&lt;/a&gt; for my
network management, even when I am not using GNOME. For wireless networking,
install the following additional packages.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; pacman -S iw wpa_supplicant dialog networkmanager network-manager-applet dhclient&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;NetworkManager&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; supports basic DHCP configuration. For full support, I have
installed &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;dhclient&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;NetworkManager&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; also supports automatic wired connection
detection and comes with curses based tool &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;nmtui&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to setup wireless connection.&lt;/p&gt;
&lt;p&gt;To enable NetworkManager to start at system startup&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; systemctl enable NetworkManager.service&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;12-reboot-now&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#12-reboot-now&quot;&gt;12. Reboot now&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;If you had performed the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;lvm&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; troubleshooting steps during &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;grub&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; install, then&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;umount&lt;/span&gt; /run/lvm&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now exit from &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;chroot&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; by typing &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;exit&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; in the shell. Unmount all the mounted
partitions with:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;umount&lt;/span&gt; -R /mnt&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Finally, reboot your machine by typing &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;reboot&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and remove the installation USB
drive. If you are not able to boot into your system at this point, boot from the
installation media again and attempt to fix the installation.&lt;/p&gt;
&lt;p&gt;If you can see a terminal with a prompt for your username, congratulations! You
have completed the first step towards building your own system.&lt;/p&gt;
&lt;p&gt;I will be writing about making your system usable and stable in the
&lt;a href=&quot;https://yashagarwal.in/notes/arch-linux-installation-guide-part-2/&quot;&gt;second&lt;/a&gt; part of this guide.&lt;/p&gt;
&lt;p&gt;Hope you enjoyed the post. Stay tuned :)&lt;/p&gt;</content:encoded></item><item><title>My Own Configuration Manager</title><link>https://yashagarwal.in/notes/my-own-configuration-manager/</link><guid isPermaLink="true">https://yashagarwal.in/notes/my-own-configuration-manager/</guid><description>Discover how to manage your Linux dotfiles efficiently with a custom Python-based configuration manager, simplifying system setup and backups.</description><pubDate>Sun, 21 Jan 2018 05:53:23 GMT</pubDate><content:encoded>&lt;p&gt;I have been using Linux since I was in my second year of undergraduate. My
experiments with the dotfiles (configuration files) also started at the same
time. For the uninformed, in Linux, it is common to configure a lot of settings
and configurations within dotfiles. Dotfiles are files in a Linux user&apos;s home
directory that begin with a dot or a full-stop character. This dot indicates to
the operating system that these files are used to store the settings of programs
like &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;vim&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; or shells like &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;bash&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; or &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;fish&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to name a few.&lt;/p&gt;
&lt;p&gt;In the beginning, I was keeping a manual backup of my dotfiles by copying them
to a folder from time to time. But the list soon started getting huge, that it
became complicated for me to keep track of the changes. Then I moved to
symlinks. I started symlinking all the dotfiles from my folder to their usual
locations. This setup worked perfectly fine, but as my collection of dotfiles
grew, It became very cumbersome for me to symlink every dotfile manually.&lt;/p&gt;
&lt;p&gt;I also tried a few tools built for this particular purpose. Some of them are
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;vcsh&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;mr&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;stow&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. These tools work just fine, but I was not willing to
learn new tools just for maintaining my dotfiles. At last, I decided to write my
tool to solve this problem. This way, there will not be any external dependency,
and this tool will also become part of my dotfiles.&lt;/p&gt;
&lt;h1 id=&quot;design&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#design&quot;&gt;Design&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The tool, in itself, is inspired by the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Configuration_file#UNIX/Linux&quot;&gt;UNIX tradition&lt;/a&gt; of
keeping configuration files for the settings of the programs. This configuration
system uses a JSON formatted dotfile.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/yashhere/ConMan&quot;&gt;Here&lt;/a&gt; is the source code for the
configuration system. Let&apos;s have a look at the file structure of the repository.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;|&lt;/span&gt;-- .backups
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;|&lt;/span&gt;   |-- 08-01-2018-15:47
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;|&lt;/span&gt;   |-- 08-01-2018-19:30
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;|&lt;/span&gt;   |-- ......
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;|&lt;/span&gt;-- configure.py
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;|&lt;/span&gt;-- current_status
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;|&lt;/span&gt;-- dotfiles
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;|&lt;/span&gt;   |-- dunst
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;|&lt;/span&gt;   |-- gtk-3.0
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;|&lt;/span&gt;   |-- i3
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;|&lt;/span&gt;   |-- ......
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;|&lt;/span&gt;-- dotfiles.json
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;|&lt;/span&gt;-- LICENSE
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;|&lt;/span&gt;-- README.md&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;During the initial setup, you need to edit the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;dotfiles.json&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file to suit your
setup. A relevant section of the JSON file is given below.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;json&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;json&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;{&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;pre&quot;&lt;/span&gt;: [
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;      &quot;name&quot;&lt;/span&gt;: &quot;cloning repository&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;      &quot;command&quot;&lt;/span&gt;: &quot;git&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;      &quot;subcommand&quot;&lt;/span&gt;: &quot;clone&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;      &quot;argument&quot;&lt;/span&gt;: &quot;https://github.com/yashhere/dotfiles.git&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  ],&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;linking&quot;&lt;/span&gt;: [
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;      &quot;name&quot;&lt;/span&gt;: &quot;bashrc&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;      &quot;src&quot;&lt;/span&gt;: &quot;dotfiles/.bashrc&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;      &quot;dest&quot;&lt;/span&gt;: &quot;.bashrc&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;      &quot;name&quot;&lt;/span&gt;: &quot;bash_profile&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;      &quot;src&quot;&lt;/span&gt;: &quot;dotfiles/.bash_profile&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;      &quot;dest&quot;&lt;/span&gt;: &quot;.bash_profile&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;      &quot;name&quot;&lt;/span&gt;: &quot;profile&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;      &quot;src&quot;&lt;/span&gt;: &quot;dotfiles/.profile&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;      &quot;dest&quot;&lt;/span&gt;: &quot;.profile&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    },&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    {&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;      &quot;name&quot;&lt;/span&gt;: &quot;i3&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;      &quot;src&quot;&lt;/span&gt;: &quot;dotfiles/i3&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;      &quot;dest&quot;&lt;/span&gt;: &quot;.config/i3&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;  ]&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;As can be seen, the JSON file has an array variable &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;linking&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, which can be used
to set the paths for each configuration file and folder. The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;configure.py&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;
script also requires a &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;dotfiles&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; folder to be present in the current directory.
The folder can be created manually, or if it is already version controlled on
GitHub, then the script can clone it. For that, you can edit the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pre&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; section
in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;dotfiles.json&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Your dotfiles and config folders go inside the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;dotfiles&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; folder. You need to
copy all your current configurations to this folder to get started.&lt;/p&gt;
&lt;p&gt;So, how does the script know where a file or folder will be linked? Simple, you
need to edit the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;dotfiles.json&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file and add source and destination locations.
For example, if you want to set up configurations of &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;i3&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to its original
location (which is, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;$HOME/.config/i3&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;), then you need to create a new JSON
object in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;linking&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; array, like this.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;json&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;json&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;{&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;name&quot;&lt;/span&gt;: &quot;i3&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;src&quot;&lt;/span&gt;: &quot;dotfiles/i3&quot;,
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#005CC5&quot;&gt;  &quot;dest&quot;&lt;/span&gt;: &quot;.config/i3&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Here the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;name&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is used to identify the configuration file, the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;src&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; parameter
is the location of your config file/folder in the dotfiles directory, and the
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;dest&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; parameter is the final destination of the file/folder. Keen observers
would notice that I have not used &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;$HOME&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; anywhere. It is understood that the
configuration will go to the current user&apos;s home directory. So the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;dest&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is
relative to the user&apos;s home directory, and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;src&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is relative to the directory
from which the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;configure.py&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; script is executed.&lt;/p&gt;
&lt;p&gt;And you are done! Now, run &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;configure.py&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, and all your dotfiles and folders
will be symlinked to their correct place.&lt;/p&gt;
&lt;p&gt;The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;current_status&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file saves all the symlink locations that are being managed
by the script, for your easy reference and to debug any error.&lt;/p&gt;
&lt;h1 id=&quot;behind-the-scenes&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#behind-the-scenes&quot;&gt;Behind the Scenes&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;A lot to cool things happen behind the scenes. The script will check if any
previous symlink exists at the given &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;dest&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; location. It removes any symlinks to
avoid redundancy. If the dest already has any dotfile or folder, then it backs
it up in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;.backups&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; under today&apos;s date and time before replacing it with a
symlink to avoid any potential data loss.&lt;/p&gt;
&lt;p&gt;I hope the article was useful. Cheers 😄&lt;/p&gt;</content:encoded></item><item><title>2017 - The Best Till Now</title><link>https://yashagarwal.in/notes/2017-the-best-till-now/</link><guid isPermaLink="true">https://yashagarwal.in/notes/2017-the-best-till-now/</guid><description>Reflecting on 2017, a life-changing year marked by academic growth, coding challenges, successful campus placement, and personal development.</description><pubDate>Sun, 31 Dec 2017 17:49:00 GMT</pubDate><content:encoded>&lt;p&gt;If I have to define 2017 in one word, that would be amazing. This year has been
a life-changing year for me. I learned a lot of new things, had some excellent
experience in the company of amazing people, had a great time in my academic
life and SSL. 2017 has been a very significant year for me, and I want to record
this memory by documenting some of the most amazing things that I learned and
experienced this year.&lt;/p&gt;
&lt;h1 id=&quot;grades&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#grades&quot;&gt;Grades&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Although I cared very little for grades for the most of my college life, this
year changed my perception of grades. I finally understood that the grades are
also equally important. I started 2017 with only one goal — getting good
grades. I studied a lot in the first half of the year, and it is because of that
time, I hold an excellent command over Computer Networks. If I have to choose
any one semester for my placement, It would be 6th semester.&lt;/p&gt;
&lt;p&gt;I invested most of my time for preparation of campus placements in the mid of
the year. Reading Data Structures and Algorithms have proven to be very
beneficial for me. However, the way I studied Data Structures, hasn&apos;t improved
my skills in real-world problem-solving skills.&lt;/p&gt;
&lt;p&gt;I did not do exceptionally well in academics in the late half of the year.
Partly because of the &lt;em&gt;after placement&lt;/em&gt; and &lt;em&gt;&quot;Dude, it is fourth year&quot;&lt;/em&gt; type of
environment around me. My final year project did not go in the right direction,
and it is one of the very few disappointments for me in &lt;em&gt;2017&lt;/em&gt;.&lt;/p&gt;
&lt;h1 id=&quot;coding&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#coding&quot;&gt;Coding&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;It is one thing which I could never excel in my undergrad life. People say that
coding is a skill and it requires practice. However, to continue doing that
practice, one needs patience, that, unfortunately, I lack. This year continued
to be the same as 2016. I could not overcome my fear of coding. I tried doing
something different in the form of
&lt;a href=&quot;https://twitter.com/_100DaysOfCode&quot;&gt;#100daysofcode&lt;/a&gt;, but couldn&apos;t continue it
after 20 days because of my preparations for campus placements. I have again
started writing code on a regular basis in late December. Looking forward to
code more frequently in 2018.&lt;/p&gt;
&lt;p&gt;Recently I started working on Debian Packaging.
&lt;a href=&quot;https://qa.debian.org/developer.php?login=praveen%40debian.org&quot;&gt;Praveen&lt;/a&gt; sir
has always been very supportive of me and answered all my ludicrous questions
very patiently. My conversation with him about free software philosophy has been
very enlightening. Debian Packaging was a very satisfying experience to be able
to give something back to the community. Now, I hold
&lt;a href=&quot;https://qa.debian.org/developer.php?login=yashagarwaljpr@gmail.com&quot;&gt;one&lt;/a&gt;
package in the unstable Debian repository and
&lt;a href=&quot;https://qa.debian.org/developer.php?login=bansaly26@gmail.com&quot;&gt;two&lt;/a&gt; more
packages in the pipeline for approval.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/HackFest1.C4gnIRVN_sjWYG.webp&quot; alt=&quot;Working on my first Debian package&quot; title=&quot;Working on my first Debian package&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4160&quot; height=&quot;2340&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/HackFest2.DogBTijh_1gEipu.webp&quot; alt=&quot;Praveen sir and team&quot; title=&quot;Praveen sir and team&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4160&quot; height=&quot;2340&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;placement&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#placement&quot;&gt;Placement&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I joined NIT Calicut due to many
&lt;a href=&quot;https://dsanghi.blogspot.com/2011/05/my-2011-list-of-recommended-csit.html&quot;&gt;reasons&lt;/a&gt;.
Placements were undoubtedly one of the most important of them. Fortunately, I
was among first few students to get placed in my batch. That moment came with a
great relief in my life.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/placement.CUeUYVd9_Z1qKV89.webp&quot; alt=&quot;A private post on FB, now public&quot; title=&quot;A private post on FB, now public&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;515&quot; height=&quot;289&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;reading&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#reading&quot;&gt;Reading&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I had started this year with an aim to read ten books and keep track of my
reading on &lt;a href=&quot;https://www.goodreads.com/user_challenges/8390620&quot;&gt;Goodreads&lt;/a&gt;. In
the end, I could not finish my goal. I did occasionally try to meet my goal, but
my excessive reliance on soft copies of the books always distracted me. Now, it
is not a surprise that I am unable to read anything on a screen. I got three
hard copy books and finished two of them. However, I could not go past more than
20 pages of any digital book, that I bought on Kindle.&lt;/p&gt;
&lt;h1 id=&quot;writing&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#writing&quot;&gt;Writing&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I have not written for the most of the year. I do think about writing
occasionally and keep a note of all the ideas that I get. However, due to my
busy schedule and my usual procrastination, I do not write that often. In 2018,
I will try to write more often.&lt;/p&gt;
&lt;h1 id=&quot;health&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#health&quot;&gt;Health&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;It is one issue where I do not put enough stress. I can divide my year into two
parts for this portion. Pre Birthday half and post Birthday half. I maintained a
daily exercise routine for the first half of the year. That helped me in many
ways. I felt more energetic, more productive and more resolute to troubles in
life. I slept at ten each day and woke up early morning. It resulted in
excellent health, which I had always lacked.&lt;/p&gt;
&lt;p&gt;However, the second half of the year was disastrous. Due to weather and other
unavoidable circumstances, I could not keep up my routine; once I came back to
college. I started sleeping late again, and that resulted in me going to docter
very often in the last two months.&lt;/p&gt;
&lt;h1 id=&quot;relations&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#relations&quot;&gt;Relations&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I continued to feel bored in the company of people. It is somewhat strange that
after getting into college, year by year, my interest in public events has
decreased gradually. It may be because of the difference in my understanding of
happiness and that of others.&lt;/p&gt;
&lt;p&gt;I built good relations with some faculties in the
&lt;a href=&quot;http://cse.nitc.ac.in/&quot;&gt;department&lt;/a&gt;, my technical skills got me some admirers,
who eventually became my &lt;em&gt;friends&lt;/em&gt;. I made some new friends from MCA also this
year. It has been a pleasant experience overall.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Looking forward to 2018 for, full of new experiences!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title>Setting Up SSH Agent in i3</title><link>https://yashagarwal.in/notes/setting-up-ssh-agent-in-i3/</link><guid isPermaLink="true">https://yashagarwal.in/notes/setting-up-ssh-agent-in-i3/</guid><description>Master SSH and GPG agent setup in i3 window manager. This guide covers key generation and configuration for a secure Linux development environment.</description><pubDate>Wed, 27 Dec 2017 14:51:09 GMT</pubDate><content:encoded>&lt;p&gt;In this post, I will write about the procedure to correctly setup SSH and GPG
agents in the i3 window manager. To follow this post, you need to have ssh-keys
and your private GPG keys ready. If you do not already have these keys with you,
I will describe the process of creating the keys.&lt;/p&gt;
&lt;h1 id=&quot;ssh&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#ssh&quot;&gt;SSH&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Generating an SSH key pair provides you with a public key and a private key. The
private key should never be given to anyone and public key, well the name itself
is self-explanatory.&lt;/p&gt;
&lt;p&gt;To create a new key pair, open a terminal and paste the text below.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;ssh-keygen&lt;/span&gt; -t rsa -b 4096 -C &quot;your_email_address&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This command will create a new ssh key pair with the given email address as the
label. Press Enter for any question asked. When it asks for the passphrase, type
a strong passphrase, otherwise leave it blank to have no password.&lt;/p&gt;
&lt;h1 id=&quot;gpg&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#gpg&quot;&gt;GPG&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;You might need to download the GPG command line tools before following the below
steps. Follow your distribution&apos;s documentation for more help.&lt;/p&gt;
&lt;p&gt;Once you have downloaded the tools, open a terminal, and type the following
command.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;gpg&lt;/span&gt; --gen-key&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;You will see something like this. Enter 1 to select the default key choice.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;gpg (GnuPG) 1.4.20; Copyright (C) 2015 Free Software Foundation, Inc.&lt;/span&gt;
&lt;span&gt;This is free software: you are free to change and redistribute it.&lt;/span&gt;
&lt;span&gt;There is NO WARRANTY, to the extent permitted by law.&lt;/span&gt;
 
&lt;span&gt;gpg: directory `/home/yash/.gnupg&apos; created&lt;/span&gt;
&lt;span&gt;gpg: new configuration file `/home/yash/.gnupg/gpg.conf&apos; created&lt;/span&gt;
&lt;span&gt;gpg: WARNING: options in `/home/yash/.gnupg/gpg.conf&apos; are not yet active during this run&lt;/span&gt;
&lt;span&gt;gpg: keyring `/home/yash/.gnupg/secring.gpg&apos; created&lt;/span&gt;
&lt;span&gt;gpg: keyring `/home/yash/.gnupg/pubring.gpg&apos; created&lt;/span&gt;
&lt;span&gt;Please select what kind of key you want:&lt;/span&gt;
&lt;span&gt;   (1) RSA and RSA (default)&lt;/span&gt;
&lt;span&gt;   (2) DSA and Elgamal&lt;/span&gt;
&lt;span&gt;   (3) DSA (sign only)&lt;/span&gt;
&lt;span&gt;   (4) RSA (sign only)&lt;/span&gt;
&lt;span&gt;Your selection?&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;At the next prompt, enter the key size. It is recommended to use the maximum key
size of 4096 bits.&lt;/p&gt;
&lt;p&gt;Enter the time duration for which the key should remain valid. Press Enter to
specify the default selection, indicating that the key does not expire.&lt;/p&gt;
&lt;p&gt;After verifying the information, enter your user information and a strong
passphrase. Afterward, GPG will start generating your key. You will see:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;text&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;We need to generate a lot of random bytes. It is a good idea to perform some other action (type on the keyboard, move the mouse,&lt;/span&gt;
&lt;span&gt;utilize the disks) during the prime generation; this gives the random number generator a better chance to gain enough entropy.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;You can now use the key (until it expires) to encrypt your data.&lt;/p&gt;
&lt;h1 id=&quot;setting-up-ssh-agent&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#setting-up-ssh-agent&quot;&gt;Setting up SSH Agent&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id=&quot;configuring-i3&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#configuring-i3&quot;&gt;Configuring i3&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Update (26/05/2018):&lt;/strong&gt; &lt;em&gt;As pointed out by
&lt;a href=&quot;https://sakshamsharma.com/&quot;&gt;Saksham&lt;/a&gt; in the comments below, this step is not
required for the setup of SSH in i3. This step can be safely ignored.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Open i3 configuration file and add an &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;exec_always&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; statement -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;exec_always&lt;/span&gt; ~/.config/i3/scripts/gnome-keyring.sh&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Obviously, you will need to change the path according to your OS. Now make a new
file in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;~/.config/i3/scripts&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; with name &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;gnome-keyring.sh&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and paste the below
text in it.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;eval&lt;/span&gt; $(/usr/bin/gnome-keyring-daemon --start --components=gpg,pkcs11,secrets,ssh)
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;export&lt;/span&gt; GNOME_KEYRING_CONTROL GNOME_KEYRING_PID GPG_AGENT_INFO SSH_AUTH_SOCK&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;(Assuming that you already have installed gnome-keyring)&lt;/p&gt;
&lt;p&gt;Now, reload the i3.&lt;/p&gt;
&lt;h2 id=&quot;configuring-ssh&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#configuring-ssh&quot;&gt;Configuring SSH&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Update (26/05/2018):&lt;/strong&gt; &lt;em&gt;This step is also optional. Thanks to
&lt;a href=&quot;https://sakshamsharma.com/&quot;&gt;Saksham&lt;/a&gt; for pointing it out.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Open &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;~/.ssh/config&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file and add following content to it -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;Host&lt;/span&gt; *
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  AddKeysToAgent&lt;/span&gt; yes
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;  IdentityFile&lt;/span&gt; /home/&amp;#x3C;your username&gt;/.ssh/id_rsa&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Replace &amp;#x3C;your username&gt; accordingly.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-bashrc&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#setting-up-bashrc&quot;&gt;Setting up .bashrc&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I am not using a login shell, and I could not find any suitable method to source
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;~/.profile&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; or &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;~/.bash_profile&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; on login in i3. So I added my configuration to
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;~/.bashrc&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file. I know it is a hack, but it works well for me without much
headache.&lt;/p&gt;
&lt;p&gt;Open &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;~/.bashrc&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file and add following lines to the end of the file.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;if&lt;/span&gt; [ -f ~/.ssh/agent.env ] ; then
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;    .&lt;/span&gt; ~/.ssh/agent.env &gt; /dev/null
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    if&lt;/span&gt; ! kill -0 $SSH_AGENT_PID &gt; /dev/null 2&gt;&amp;#x26;1; then
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;        echo&lt;/span&gt; &quot;Stale agent file found. Spawning a new agent. &quot;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;        eval&lt;/span&gt; `ssh-agent | tee ~/.ssh/agent.env`
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;        ssh-add&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    fi&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;else&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;    echo&lt;/span&gt; &quot;Starting ssh-agent&quot;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;    eval&lt;/span&gt; `ssh-agent | tee ~/.ssh/agent.env`
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;    ssh-add&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;fi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;It will automatically start an &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;ssh-agent&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; if it is not already running.
Otherwise, it attaches to a previously running agent.&lt;/p&gt;
&lt;p&gt;Now log out and log in again to see if ssh-agent works. Open a terminal and run
the command &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;ssh-add -l&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. It will show you the hash value of your ssh-key, which
is loaded by the ssh-agent.&lt;/p&gt;
&lt;p&gt;That is all for today. Thank you for reading!&lt;/p&gt;</content:encoded></item><item><title>Setting up ALM Octane with Docker Compose</title><link>https://yashagarwal.in/notes/setting-up-alm-octane-with-docker-compose/</link><guid isPermaLink="true">https://yashagarwal.in/notes/setting-up-alm-octane-with-docker-compose/</guid><description>Simplify ALM Octane deployment with Docker Compose. Learn to set up multi-container environments for Oracle DB, Elastic Search, and the Octane Server.</description><pubDate>Tue, 26 Dec 2017 15:23:35 GMT</pubDate><content:encoded>&lt;p&gt;Recently, I got a chance to set up ALM Octane on one of my university servers
for a course project. From the support page of ALM Octane:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ALM Octane is a web-based application lifecycle management platform that
enables teams to collaborate easily, manage the product delivery pipeline, and
visualize the impact of changes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&quot;precursor&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#precursor&quot;&gt;Precursor&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;My &lt;a href=&quot;http://cse.nitc.ac.in/&quot;&gt;department&lt;/a&gt; insists on using open-source software (a
plus point, indeed!). But ALM Octane has Oracle DB/MSSQL as a dependency. My
professor was not very enthusiastic about installing a proprietary database on
the server. So I came up with a different approach. I set up this database
(&lt;a href=&quot;https://www.oracle.com/database/technologies/appdev/xe.html&quot;&gt;free version&lt;/a&gt; of
Oracle DB, the Oracle Database 11g Express Edition) in a Docker container. ALM
Octane has three components – Oracle DB, Elastic Search, and the Octane Server
itself. The problem was to handle the condition that these three components
should be installed on different machines. I decided to use three separate
Docker containers for this isolation and then configured them to communicate
with each other with docker-compose.&lt;/p&gt;
&lt;h2 id=&quot;wait--docker-compose&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#wait--docker-compose&quot;&gt;Wait … Docker Compose?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;(Skip this if already know about Docker and Compose)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Docker-compose is a tool to define and run multi-container Docker
applications. Compose uses a compose file to configure the services used by
the applications. Then all the services and the application can be run by
using a single command.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So before reading this article any further, if you do not know about
docker-compose, go and read about it.&lt;/p&gt;
&lt;h1 id=&quot;the-problem&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-problem&quot;&gt;The Problem&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Three primary services are required for the proper functioning of the Octane
Server – Octane, Oracle DB and Elastic Search. The difficulty was to set up
adequate configuration options for these services and the appropriate setup for
communication between them. I searched on Docker Hub for any pre-built images.
Fortunately, I found some pre-built Docker images for my purpose. So I started
writing my config file.&lt;/p&gt;
&lt;h1 id=&quot;the-solution&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-solution&quot;&gt;The Solution&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Here is my config file for easy reference.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;yaml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;version&lt;/span&gt;: &quot;2&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;services&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  octane_oracle&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    image&lt;/span&gt;: alexeiled/docker-oracle-xe-11g
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    shm_size&lt;/span&gt;: 2g
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    mem_limit&lt;/span&gt;: 4g
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  octane_es&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    image&lt;/span&gt;: elasticsearch:2.4
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    environment&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;ES_HEAP_SIZE=4G
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    mem_limit&lt;/span&gt;: 4g
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;  octane&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    image&lt;/span&gt;: hpsoftware/almoctane
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    ports&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;&quot;8080:8080&quot;
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    volumes&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;/opt/octane/conf:/opt/octane/conf
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;/opt/octane/log:/opt/octane/log
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;/opt/octane/repo:/opt/octane/repo
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    links&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;octane_oracle
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;octane_es
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    mem_limit&lt;/span&gt;: 4g
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    env_file&lt;/span&gt;:
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;      - &lt;/span&gt;./octane.env&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The configuration options in the code are for a system with RAM of 8GB. The
options must be tuned for the best performance before deploying on the
production server.&lt;/p&gt;
&lt;p&gt;In the code, I have exposed port &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;8080&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; of the Octane Docker container to the
port 8080 of the host machine. It will make sure that we can access the Octane
application on &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;localhost:8080&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. The &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;octane.env&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file contains three variables
for easy site management.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;SERVER_DOMAIN&lt;/span&gt;=&quot;your domain name&quot;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;ADMIN_PASSWORD&lt;/span&gt;=&quot;your password&quot;
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;#This disables the minimum memory check to enable to run on smaller machines.&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;DISABLE_VALIDATOR_MEMORY&lt;/span&gt;=true&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now, if you try to run the container with &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;docker-compose up&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, you will
encounter various validation errors. It is because, before starting the server,
you need to adjust some settings. If you noticed in the config file, there is a
section to define volumes. These volumes are persistent and are used to keep
changes saved between two docker-compose runs. I have mapped three volumes from
the Docker container to the host machine. So you can now edit the files in the
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/opt/octane/&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; folder on the host machine, and changes will reflect in the
Docker container. The file where you will have to make changes is
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/opt/octane/conf/setup.xml&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;You can read the documentation of ALM Octane to find out which settings to be
changed. Once you do the necessary changes, fire up the command
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;docker-compose up&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and wait for some time. Docker Compose will finish
processing, and the server can be accessed on &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;http://localhost:8080&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; on the
host machine. While deploying it on the production server, make sure that your
network administrator has opened the port 8080 for your server. Otherwise, the
site will not be accessible. Also, the docker-compose can be run in the
background by issuing command &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;docker-compose up -d&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;</content:encoded></item><item><title>Fixing Hindi Fonts in Arch Linux</title><link>https://yashagarwal.in/notes/fixing-hindi-fonts-in-arch-linux/</link><guid isPermaLink="true">https://yashagarwal.in/notes/fixing-hindi-fonts-in-arch-linux/</guid><description>A quick guide to fix distorted Hindi font rendering in Arch Linux browsers, enhancing readability and user experience.</description><pubDate>Tue, 17 Oct 2017 16:25:53 GMT</pubDate><content:encoded>&lt;p&gt;When viewing Hindi content in any browser in Arch Linux, the rendering looks
weird.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/hindi_font_before.BziM3wFF_1bL75h.webp&quot; alt=&quot;before applying the fix&quot; title=&quot;before applying the fix&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;814&quot; height=&quot;104&quot;&gt;&lt;/p&gt;
&lt;p&gt;It doesn&apos;t look good, right! I&apos;ll try to fix this issue in this post. You might
need to install the appropriate
&lt;a href=&quot;https://wiki.archlinux.org/index.php/fonts&quot;&gt;font support&lt;/a&gt; in Arch Linux before
applying this fix. The suitable package for installing Indic Language support is
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;ttf-indic-otf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Now go to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/usr/share/fonts/TTF&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and take the backup of two fonts &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;FreeSans.ttf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;
and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;FreeSerif.ttf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. Now delete these two fonts from the directory. Restart the
browser and see the difference.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/hindi_font_after.BFEfLqlo_1QtXDw.webp&quot; alt=&quot;after applying the fix&quot; title=&quot;after applying the fix&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;815&quot; height=&quot;103&quot;&gt;&lt;/p&gt;
&lt;p&gt;This bug is reported in
&lt;a href=&quot;https://bugs.launchpad.net/ubuntu/+source/chromium-browser/+bug/856736&quot;&gt;this&lt;/a&gt;
bug report in 2011. I don&apos;t know why nobody has fixed it yet. Or maybe I was not
able to find the proper solution. This workaround is also given in the same bug
report.&lt;/p&gt;
&lt;p&gt;I hope this helps. :)&lt;/p&gt;</content:encoded></item><item><title>Mounting NTFS partitions on Arch Linux</title><link>https://yashagarwal.in/notes/mounting-ntfs-partitions-on-arch-linux/</link><guid isPermaLink="true">https://yashagarwal.in/notes/mounting-ntfs-partitions-on-arch-linux/</guid><description>Learn how to easily mount Windows NTFS partitions on Arch Linux for seamless file access, configuring Polkit for standard user permissions.</description><pubDate>Tue, 14 Mar 2017 10:30:36 GMT</pubDate><content:encoded>&lt;p&gt;Yesterday I installed Arch Linux once again. A clean, bloat-free desktop with
Budgie Desktop environment with some must-have open source tools. Everything
worked fine except WiFi and some minor bugs in Budgie(I don&apos;t know whether it is
a bug in Budgie or just a wrong setting). I also faced the problem of mounting
Windows NTFS volumes on the user&apos;s wish. Arch Linux wiki has details about how
to automount partitions on start-up. Still, I had a tough time to find out what
exactly needs to be done to simulate the behavior of Ubuntu-like distribution on
the mounting of NTFS drives. I got a hint from Arch Linux Wiki about the Polkit
configuration setting, which can be used to allow a standard user to mount
partitions. Here is a solution that I found after a long search on various Arch
Linux Community pages.&lt;/p&gt;
&lt;p&gt;You will need to install &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;ntfs-3g&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;polkit&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;udisks2&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to use this code.
Please refer to &lt;a href=&quot;https://wiki.archlinux.org/index.php/Udisks&quot;&gt;Arch Wiki&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I think when using Gentoo, you will also need to compile the support for the
NTFS file system in Kernel also. Please see
&lt;a href=&quot;https://wiki.gentoo.org/wiki/NTFS&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Add the following code to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/polkit-1/rules.d/10-udisks2.rules&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;vim&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;vim&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;//&lt;/span&gt; Allow udisks2 to mount devices without authentication for users in the &quot;wheel&quot; group.
&lt;span style=&quot;--shiki-dark:#DCBDFB;--shiki-light:#6F42C1&quot;&gt;polkit.addRule&lt;/span&gt;(function(action, subject) {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    if&lt;/span&gt; ((action.id:= &quot;org.freedesktop.udisks2.filesystem-mount-system&quot; ||
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        action.id:&lt;/span&gt;= &quot;org.freedesktop.udisks2.filesystem-mount&quot;) &amp;#x26;&amp;#x26;
&lt;span style=&quot;--shiki-dark:#DCBDFB;--shiki-light:#6F42C1&quot;&gt;        subject.isInGroup&lt;/span&gt;(&quot;wheel&quot;)) {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;            return&lt;/span&gt; polkit.Result.YES;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;);&lt;/span&gt;
 
&lt;span style=&quot;--shiki-dark:#DCBDFB;--shiki-light:#6F42C1&quot;&gt;polkit.addRule&lt;/span&gt;(function(action, subject) {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;   if&lt;/span&gt; ((action.id:= &quot;org.freedesktop.udisks.filesystem-mount-system-internal&quot;) &amp;#x26;&amp;#x26;
&lt;span style=&quot;--shiki-dark:#DCBDFB;--shiki-light:#6F42C1&quot;&gt;        subject.isInGroup&lt;/span&gt;(&quot;wheel&quot;)) {
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;            return&lt;/span&gt; polkit.Result.YES;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;        }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    }&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now you will be able to mount NTFS partition without any problem. :)&lt;/p&gt;</content:encoded></item><item><title>FOSSMeet&apos;17</title><link>https://yashagarwal.in/notes/fossmeet-17/</link><guid isPermaLink="true">https://yashagarwal.in/notes/fossmeet-17/</guid><description>Reflect on FOSSMeet&apos;17, sharing experiences as an organizer, lessons learned in team management, and observations on FOSS community engagement.</description><pubDate>Mon, 13 Mar 2017 21:03:16 GMT</pubDate><content:encoded>&lt;p&gt;One more edition of FOSSMeet&apos;17 was successfully organized in NIT Calicut
recently. As an active member of the organizing team of this year&apos;s edition
(though I sidelined myself at the end) and a keen but silent observer, I want to
share my experience, ideas, and some observations through this post.&lt;/p&gt;
&lt;h1 id=&quot;marketing-website&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#marketing-website&quot;&gt;Marketing Website&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We started planning the next edition of FOSSMeet sometime around September. Not
many people were interested in planning. Anyway, Shrimadhav and I began working
on the marketing website. The first design was straightaway rejected by Piyush
and Simsar, which I feel, was fruitful. In the process, I learned some critical
insights about planning, team management, and design of a user-friendly website.
So I again started working on the site. The end product was clean, good looking,
and simple (at least I was happy with it :P).&lt;/p&gt;
&lt;p&gt;In the meanwhile, Amal and I started thinking about ideas, how can we
restructure the FOSSCell, which had not seen a single activity (except those
trademark events which were conducted just for formality) in years. I now
understand that it was a mistake. It is a prerequisite about open source
contribution that you should contribute to the products which you use in day to
day life. When we started thinking about the FOSSCell, we didn&apos;t know about any
of these points. We conducted a formal test(more of a filtering process), then
we had a small meeting with the selected 2nd years about the FOSSCell, and we
discussed the plan for next semester. Then everyone left for winter vacations.&lt;/p&gt;
&lt;h1 id=&quot;a-period-of-self-evaluation&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#a-period-of-self-evaluation&quot;&gt;A period of self-evaluation&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;In the winter holidays, we tried to have some IRC discussions, which again was
somewhat successful because of the efforts from Shrimadhav and Simsar. It was a
new experience for me also, but still, I tried to attend as much as I could. I
also took one session on Git and Vim, which again was an entirely new experience
for me.&lt;/p&gt;
&lt;p&gt;In the winter vacation, I found some time to think about the purpose of FOSSMeet
and FOSSCell and in what direction we were heading. I somehow understood that I
was not qualified enough to guide someone about open source contribution or in
general FOSS ideology, because I, myself was not contributing anything to open
source community, and had no characteristic of a FOSS enthusiast. So I somehow
lost my interest in FOSSCell and even in Linux. Shrimadhav asked me my ideas
about FOSSCell activities, but I had no clue what to say. So that&apos;s how the
FOSSCell again died without achieving anything significant. I feel it was my
mistake. I still feel sad about this. :(&lt;/p&gt;
&lt;h1 id=&quot;fossmeet-time&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#fossmeet-time&quot;&gt;FOSSMeet time&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;So as the FOSSMeet&apos;s dates came near, people started coming for &lt;em&gt;volunteering&lt;/em&gt;.
It was good for the event, though. The funnel was already up last semester, and
we were getting some good proposals also. FOSSMeet also went superbly. All the
participants gave excellent reviews. There were some hiccups also, The Campus
Internet Connectivity being the most significant one. There were some issues in
SSL also, again, somewhere I hold an important responsibility. All in all,
everybody praised the event and organization of the event. This year, we tried
to reduce the use of plastics, and I feel that we were quite successful.&lt;/p&gt;
&lt;h1 id=&quot;my-observations&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#my-observations&quot;&gt;My Observations&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;There were some issues about the event, which I didn&apos;t like at a personal level.
I sometimes think about what is the motive for conducting some activities in
colleges. An event like FOSSMeet which attract the attention of all FOSS
enthusiasts from all over Kerala has a huge potential of inspiring the young
folks of NIT Calicut. We somehow succeed in that motive, but what about the
situation after FOSSMeet. The enthusiasm about FOSS should not last just for two
days, but we cannot blame others for the condition. I don&apos;t have a proper idea
about the FOSS because there was no proper guidance from my senior batches. I
learned many things in the workshops organized by CSEA, in fact, I first learned
the proper use of Linux Shell in the Linux workshop conducted by CSEA (and
FOSSCell, at least for formality). But you can&apos;t ask them to do everything. I
think they are already overloaded. But there were no such workshops by FOSSCell.&lt;/p&gt;
&lt;p&gt;Second, the curriculum of the NITC CSE department focuses more on the
theoretical side of Computer Science, which is good. But it negatively affects
student activities outside the classroom. That is one of the primary reasons why
we cannot produce more GSoC participants or why don&apos;t we have more open source
enthusiasts.&lt;/p&gt;
&lt;p&gt;Third, one of the speakers in FOSSMeet mentioned one fundamental flaw in the
structure of the organizing team of FOSSMeet. It doesn&apos;t have any representation
from other branches. FOSSMeet has become an event for CSE folks, where people
from different departments do not take any interest. I think publicity was a
major issue here. I don&apos;t believe that there was any publicity done to explain
FOSSMeet to the students of other branches. (If I am wrong here, please correct
me).&lt;/p&gt;
&lt;p&gt;Fourth, people are ready to &lt;em&gt;volunteer&lt;/em&gt; for organizing an event, but they do not
want to come and attend the workshops. FOSSMeet is held by individuals who have
no previous experience of FOSS and have no intention to dive into open source
community any time soon. FOSSMeet has become a tradition that is continued every
year because it happened the previous year also. I do not feel that enthusiasm
to promote FOSS in FOSSMeet because we are organizing it to keep the legacy. I
am not saying that whatever effort organizers put in conducting FOSSMeet&apos;17 was
not significant. I am not the right person to blame them because I was also part
of the same team. But still, I feel that FOSSMeet has lost its original motive
to promote FOSS culture in NITC. It encourages more people from outside NITC,
but inside NITC, it is just one of those many events organized by random clubs.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;It&apos;s been an interesting one year for me after becoming SS Lab Admin because I
started taking part in department activities that I always wanted to do. Being a
member of the organizing team of FOSSMeet&apos;17 was again a learning experience for
me. I learned many new things, in SSL and outside SSL too. I committed some
mistakes also in making the right decisions at the right moment, but that&apos;s how
I learn. So no regrets. :) I hope that I will find time next year for FOSSMeet,
although I would prefer to attend FOSSMeet as a participant observing everything
silently rather than being a part of the organizing team.&lt;/p&gt;</content:encoded></item><item><title>Setting up Hugo automatic deployment to Github with Wercker</title><link>https://yashagarwal.in/notes/setting-up-hugo-automatic-deployment-to-github-with-wercker/</link><guid isPermaLink="true">https://yashagarwal.in/notes/setting-up-hugo-automatic-deployment-to-github-with-wercker/</guid><description>Automate your Hugo blog deployment to GitHub Pages. Learn to set up continuous integration with Wercker for seamless static site publishing.</description><pubDate>Wed, 22 Feb 2017 08:07:56 GMT</pubDate><content:encoded>&lt;p&gt;Recently, I again migrated my blog from Pelican to Hugo. So till now, I have
experimented with Wordpress, Jekyll, Pelican, and Hugo. Without any doubt, Hugo
is the simplest to set up. This time, I have setup Hugo in Windows, as I think,
in my system, I reinstall Windows OS much less frequently than the Linux. So
that way, it will be less painful for me to set up the blog again.&lt;/p&gt;
&lt;p&gt;In this post, I will list all the process which I used to set up automatic
deployment of Hugo generated site to Github pages using Wercker. In the
beginning, I was trying to use Travis-CI, but then I read about Wercker
somewhere. I was impressed with the integration of Wercker with Hugo and the
availability of many its community-generated &quot;steps&quot; for the build and deploy
process.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gohugo.io/getting-started/&quot;&gt;Hugo Docs&lt;/a&gt; already have a fantastic
&lt;a href=&quot;https://discourse.gohugo.io/t/automated-hugo-deployments-anywhere-using-wercker/539&quot;&gt;documentation&lt;/a&gt;
for setting up Hugo with Wercker, but it is outdated. Other documentations
available on-line is also obsolete. Wercker has changed many functionalities in
its platform, which made it difficult for me to set up things correctly. But
after hours of trial and error cycle, I was able to build and deploy my static
files successfully.&lt;/p&gt;
&lt;p&gt;Here I would like to share the issues I encountered and the tweaks I&apos;ve made.
The source codes of this site can be found
&lt;a href=&quot;https://github.com/yashhere/yashhere.github.io&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;project-pages-or-user-pages&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#project-pages-or-user-pages&quot;&gt;Project Pages or User Pages&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Two types of sites are supported on Github Pages, User Site, and Project Site.
User Sites will serve the files stored in the master branch of the repository
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;https://github.com/user_name/user_name.github.io&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; at the address
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;https://user_name.github.io.&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; For the Project sites, everything under the
gh-pages will be served at the address &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;https://repo_name.github.io&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;My site is a User site, so I wanted all the static files to be saved in the
master branch. As Hugo generates all the static files under &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;public&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; directory,
I needed another branch to store my source files. So my made a new branch
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;source&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, which will save all the source files for my blog. Don&apos;t forget to
remove the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;.git&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; folder from the theme folder. Otherwise, the build will fail
at a later stage. You can try using the git submodule feature to avoid this
issue. I created a repository &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;yash2696.github.io&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; in Github also.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;git&lt;/span&gt; init                       #initialized git repository in site root
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;git&lt;/span&gt; checkout -b source         #created new branch source
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;git&lt;/span&gt; remote add origin [https://github.com/yash2696/yash2696.github.io](https://github.com/yashhere/yashhere.github.io)
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;git&lt;/span&gt; add .
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;git&lt;/span&gt; commit -m &quot;Initial Commit&quot;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;git&lt;/span&gt; push origin source&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Then I initialized my master branch as a orphan branch.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;git&lt;/span&gt; checkout --orphan master
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;git&lt;/span&gt; rm -rf .
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;rm&lt;/span&gt; -f &apos;.gitignore&apos;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;echo&lt;/span&gt; &quot;#Your repository name&quot; &gt; README.md
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;git&lt;/span&gt; add README.md
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;git&lt;/span&gt; commit -a -m &quot;Initial Commit&quot;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;git&lt;/span&gt; push origin master&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;automatic-deployment-using-wrecker&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#automatic-deployment-using-wrecker&quot;&gt;Automatic deployment using Wrecker&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;It is straightforward to build a Hugo site. Invoke &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;hugo&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; command under your
root directory, Hugo will create a public folder which will contain all your
content, static files, etc. Then push this directory to Github, and voila, your
site is up!&lt;/p&gt;
&lt;p&gt;What if a single push to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;source&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; branch can trigger all the process for you
automatically. Here the magic of continuous integration(CI) comes into the
picture. A free Wercker account can be easily created and hooked to the Github
account and a new application from a chosen repository. After setting up
everything, a push to the development branch will automatically trigger the
Wercker. One of the most significant advantages of using Wercker is its
extensive collection of user-made and well documented &quot;steps&quot;. In this post, I
will use two steps, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;build hugo&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;deploy to Github&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/wercker-steps.Dk_dWTKi_M96rS.webp&quot; alt=&quot;Wercker → Registry → steps&quot; title=&quot;Wercker → Registry → steps&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1332&quot; height=&quot;251&quot;&gt;&lt;/p&gt;
&lt;p&gt;The first task is to create a &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;wercker.yml&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file. It will tell Wercker which all
actions, it should perform. Here is my
&lt;a href=&quot;https://raw.githubusercontent.com/yash2696/yash2696.github.io/source/wercker.yml&quot;&gt;wercker.yml&lt;/a&gt;
for reference. In this, I have used two pipelines, &lt;em&gt;build&lt;/em&gt; and &lt;em&gt;deploy&lt;/em&gt;. Please
follow the official docs for the more detailed steps. I will list all the
problems which I face while setting up things properly.&lt;/p&gt;
&lt;h2 id=&quot;build&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#build&quot;&gt;Build&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Following the official guide, I used this
&lt;a href=&quot;https://github.com/ArjenSchwarz/wercker-step-hugo-build&quot;&gt;step&lt;/a&gt; to trigger Hugo
to build HTML pages. I had already removed git repository information from the
theme folder, so this step finished successfully. If you haven&apos;t, you may add
the following piece of code in your build step.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;yml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;yml&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;- &lt;/span&gt;script:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    name&lt;/span&gt;: install git
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;    code&lt;/span&gt;: |
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        apt-get update&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;        apt-get install git -y&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;    - &lt;/span&gt;script:
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;        name&lt;/span&gt;: initialize git submodules
&lt;span style=&quot;--shiki-dark:#8DDB8C;--shiki-light:#22863A&quot;&gt;        code&lt;/span&gt;: |
&lt;span style=&quot;--shiki-dark:#96D0FF;--shiki-light:#032F62&quot;&gt;            git submodule update --init --recursive&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;deploy&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#deploy&quot;&gt;Deploy&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There is no concept named &quot;Add Deploy Target&quot; in Wercker as of now. Most of the
on-line tutorials follow this process which is outdated. Now Wercker uses a
concept called &quot;Workflows in Pipelines&quot;.&lt;/p&gt;
&lt;p&gt;For new interface, even if you add a deploy stage in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;wercker.yml&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, you will
have to create a new pipeline &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;deploy&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; under the Workflows tab. After creating
the pipeline, the &quot;YML Pipeline name&quot; must be set to the deploy stage name,
which in this case is &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;deploy&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;In &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;deploy&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; stage, I used this
&lt;a href=&quot;https://app.wercker.com/applications/55af22c5f32b86a9290ec706/tab/details/&quot;&gt;step&lt;/a&gt;(broken
link) to deploy the built site to Github. Each pipeline starts from scratch, so
for the deploy pipeline, the git package needs to be installed again. One also
has to set up the environment variable &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;$GIT_TOKEN&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to each pipeline, acquired
from Github setting.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/wercker-pipeline.D3dtXiQ6_ZEykX.webp&quot; alt=&quot;Wercker Pipeline&quot; title=&quot;Wercker Pipeline&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1317&quot; height=&quot;344&quot;&gt;&lt;/p&gt;
&lt;p&gt;You need to generate a new access token for your deploy stage from Github
settings.
&lt;img src=&quot;https://yashagarwal.in/_astro/wercker-access-token.D-IIskkU_Z2aSTS2.webp&quot; alt=&quot;Github Access Token&quot; title=&quot;Github Access Token&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;835&quot; height=&quot;402&quot;&gt;&lt;/p&gt;
&lt;p&gt;After adding the deploy stage, add the token you obtained from the Github to
Environmental Variables in deploy pipeline.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/wercker-token.BULk5Ej2_Z2qU81C.webp&quot; alt=&quot;Wercker Token&quot; title=&quot;Wercker Token&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1333&quot; height=&quot;363&quot;&gt;&lt;/p&gt;
&lt;p&gt;On the next push to your development branch, Wercker will automatically build
the site and deploy it on Github Pages.&lt;/p&gt;</content:encoded></item><item><title>Setting up Python Development Environments</title><link>https://yashagarwal.in/notes/setting-up-python-development-environments/</link><guid isPermaLink="true">https://yashagarwal.in/notes/setting-up-python-development-environments/</guid><description>Master Python development environments. Learn to use pip, virtualenv, and virtualenvwrapper for efficient package management and isolated project setups.</description><pubDate>Sun, 09 Oct 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently I was searching for Python projects on Github for contribution. Every
single project I found, had a thing common among them. In every project&apos;s
contribution guide, it was asked to set up the virtual environment for the
project. What the heck is this virtual environment and how does it work?&lt;/p&gt;
&lt;p&gt;As a beginner to open source projects, the problem I faced, in the beginning,
was how to set up the development environments for the projects I was looking
at. I searched the Internet, I found some articles, but they were not complete.
So I decided to write this guide, which will be useful for me in future also.&lt;/p&gt;
&lt;p&gt;Python uses &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pip&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; for package management.&lt;/p&gt;
&lt;h1 id=&quot;installing-pip&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#installing-pip&quot;&gt;Installing pip&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pip&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; depends on setuptools library, which is in official Ubuntu repositories.
To install it for python2 -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; apt-get install python-setuptools&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Then install &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pip&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; using -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; apt-get install python-pip&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;and for python3 -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; apt-get install python3-setuptools&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Then install &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pip&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; using -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; apt-get install python3-pip&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;It should install &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pip&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; on your system for both python versions. &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pip&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is very
easy to use. It will take care of every single package you may require for your
project.&lt;/p&gt;
&lt;h2 id=&quot;installing-a-package-using-pip&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#installing-a-package-using-pip&quot;&gt;Installing a package using pip&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# it will search and install [package]&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;pip&lt;/span&gt; install [package]
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;pip&lt;/span&gt; install django&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;If you are using python3, then don&apos;t forget to use &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pip3&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pip&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; can be used to install a specific version of package also.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# it will search and install [package] with [version]&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;pip&lt;/span&gt; install [package]==[version]
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;pip&lt;/span&gt; install django==1.6.5&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;uninstalling-a-package-using-pip&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#uninstalling-a-package-using-pip&quot;&gt;Uninstalling a package using pip&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# it will search and uninstall [package]&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;pip&lt;/span&gt; uninstall [package]
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;pip&lt;/span&gt; uninstall django&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;upgrading-a-package-using-pip&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#upgrading-a-package-using-pip&quot;&gt;upgrading a package using pip&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# it will upgrade [package] to latest version&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;pip&lt;/span&gt; install --upgrade [package]
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;pip&lt;/span&gt; install --upgrade django&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;creating-list-of-all-packages-with-pip&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#creating-list-of-all-packages-with-pip&quot;&gt;Creating list of all packages with pip&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is one of most used and most useful feature of &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pip&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. It allows you to make a
list of all the dependencies of your project.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# it will output the file to current directory&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;pip&lt;/span&gt; freeze &gt; [file_name.txt]&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;All these commands above will install the packages globally. But that&apos;s not what
is desired. &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;virtualenv&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; comes to our rescue here.&lt;/p&gt;
&lt;h1 id=&quot;virtualenv&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#virtualenv&quot;&gt;Virtualenv&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;virtualenv&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; solves a very particular problem; it allows multiple python
projects that have different and often conflicting dependencies, to coexist on
the same system.&lt;/p&gt;
&lt;p&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;virtualenv&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; solves this problem by creating different isolated development
environments for your projects. An environment is a folder which contains
everything; your project needs to work properly.&lt;/p&gt;
&lt;h2 id=&quot;installing-virtualenv&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#installing-virtualenv&quot;&gt;Installing virtualenv&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By default, if you install &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;virtualenv&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; using &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pip&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, it will use system&apos;s
default python to create virtual environments. To overcome this problem, we will
install &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;virtualenv&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; using ubuntu package manager.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; apt-get install python-virtualenv&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;installing-virtualenvwrapper&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#installing-virtualenvwrapper&quot;&gt;Installing virtualenvwrapper&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;virtualenvwrapper&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; provides some set of commands which makes working with
virtual environments much easier.&lt;/p&gt;
&lt;p&gt;To install it -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; pip install virtualenvwrapper&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pip&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;virtualenv&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;virtualenvwrapper&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; are the only packages which you will
need to install globally. All other per project packages will be installed in
respective virtual environments.&lt;/p&gt;
&lt;p&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;virtualenvwrapper&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; also places all your virtual environments in one place. It
makes working with projects very easy.&lt;/p&gt;
&lt;p&gt;Now open your &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;.bashrc&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and add these two lines to the end -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# All your projects will be saved in python-dev folder&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;export&lt;/span&gt; PROJECT_HOME=~/python-dev
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# ~/python-dev/virtualenvs will contains python interpreters for each project.&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;export&lt;/span&gt; WORKON_HOME=~/python-dev/virtualenvs
 
&lt;span style=&quot;--shiki-dark:#768390;--shiki-light:#6A737D&quot;&gt;# source the virtualenvwrapper script&lt;/span&gt;
&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;source&lt;/span&gt; /usr/local/bin/virtualenvwrapper.sh&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;You can change &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;python-dev&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to any name you wish. Your virtual environments will
be created at that location.&lt;/p&gt;
&lt;p&gt;Now restart your terminal to source the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;.bashrc&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; or use -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#6CB6FF;--shiki-light:#005CC5&quot;&gt;source&lt;/span&gt; .bashrc&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h2 id=&quot;basic-usage&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#basic-usage&quot;&gt;Basic Usage&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Create a virtual environment -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;mkvirtualenv&lt;/span&gt; myproject&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;It will create &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;myproject&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; folder in the python-dev directory. To activate this
project -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;workon&lt;/span&gt; myproject&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Alternatively you can create project using &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;mkproject&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; command. It will create a
virtual environment as well as a project directory in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;$PROJECT_HOME&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, which
is &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;cd&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;-ed into when you &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;workon&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; myproject.&lt;/p&gt;
&lt;p&gt;Don&apos;t forget to deactivate current project when you switch between different
projects.&lt;/p&gt;
&lt;p&gt;To deactivate a project -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;deactivate&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;To delete a virtual environment -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;rmvirtualenv&lt;/span&gt; myproject&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;List all environments -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;lsvirtualenv&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;it will also list all virtual environments -&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;workon&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Please refer to virtualenvwrapper documentation for
&lt;a href=&quot;https://virtualenvwrapper.readthedocs.io/en/latest/command_ref.html&quot;&gt;full list of virtualenvwrapper commands&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;virtualenvwrapper also provides the tab-completion feature which is very handy
when you have a lot of projects to work with.&lt;/p&gt;
&lt;p&gt;That&apos;s it. Hope you liked the post. 😄&lt;/p&gt;</content:encoded></item><item><title>Custom Arch Linux setup with Openbox</title><link>https://yashagarwal.in/notes/custom-arch-linux-setup-with-openbox/</link><guid isPermaLink="true">https://yashagarwal.in/notes/custom-arch-linux-setup-with-openbox/</guid><description>Build a custom, lightweight Arch Linux desktop environment from scratch using Openbox, focusing on configuration and personalization.</description><pubDate>Thu, 09 Jun 2016 10:20:36 GMT</pubDate><content:encoded>&lt;p&gt;After my summer vacation started, I bought a new laptop, and the first thing I
did was to install Arch Linux on it. After a standard arch installation
procedure, I started putting together my desktop environment, beginning with
ArchLinux and Openbox, and then piecing all pieces together to build a proper
desktop environment. Building a desktop this way follows the Unix Methodology;
have software that each does one thing well, and when you put them together, you
get something amazing.&lt;/p&gt;
&lt;p&gt;When I first installed Arch, I had several choices. I tried &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;xfce&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;gnome&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;
as my desktop environments. While both of them have their pros and cons, I ended
up liking none. The sole reason was the dependencies; these two software bring
with them. My only intention of installing Arch was to have something, which I
control, not like Ubuntu, where you are forced to use the preinstalled software
and when you try to uninstall something, you fear of breaking some other
program.&lt;/p&gt;
&lt;p&gt;So I end up going the route of building something up from scratch using Openbox
as a base. At this point, I have a fast, lightweight desktop that is
exceptionally stable and is genuinely my desktop as I have built it from the
ground up, choosing every application.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/desktop.Bi1Kspec_ZOCCIW.webp&quot; alt=&quot;Openbox on ArchLinux&quot; title=&quot;Openbox on ArchLinux&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1366&quot; height=&quot;768&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;window-manager&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#window-manager&quot;&gt;Window Manager&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;After the installation of Arch, the first thing I did was to install &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;openbox&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;,
a tiling window manager. You may also try other window managers like &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;awesome&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;,
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;i3&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;fluxbox&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, etc. but I chose Openbox because it is used everywhere.
Thus there is a plethora of information out there about customizing it.&lt;/p&gt;
&lt;p&gt;For our window manager to show up, it needs to be added either in a login
manager or user&apos;s &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;~/.xinitrx&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file. There is a default version of this file
that contain some code which we may want to retain, so rather than making this
file from scratch, copy the default version of the file to the user&apos;s home
directory.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;cp&lt;/span&gt; /etc/X11/xinit/xinitrc ~/.xinitrc&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Now add the command &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;exec Openbox-session&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to the end of the file. Remember that
the system will ignore the lines following this command. An Openbox session
should be able to be started by entering the command &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;startx&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;An openbox session can be started automatically upon login using shell&apos;s startup
script. Add following to the shell&apos;s startup script, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;~/.bash_profile&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; for bash
and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;~/.zprofile&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; for zsh.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;[[ &lt;/span&gt;-z $DISPLAY &amp;#x26;&amp;#x26; $XDG_VTNR -eq 1 ]] &amp;#x26;&amp;#x26; exec startx&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;configuring-openbox&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#configuring-openbox&quot;&gt;Configuring Openbox&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Setting up openbox is quite simple. Four files make the basis of openbox
configuration. They are &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;rc.xml&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;autostart&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;menu.xml&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;environment&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.
These files controls everything about the window manager.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;rc.xml&lt;/strong&gt;: Determine the behavior and settings of overall Openbox session&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;autostart&lt;/strong&gt;: Contains a list of applications to be launched with the window
manager&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;menu.xml&lt;/strong&gt;: It makes the right-click context menu of the desktop&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;environment&lt;/strong&gt;: Can be used to export and set relevant environmental
variables&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the configuration of Openbox, it is necessary to create a local Openbox
profile in the user&apos;s home directory. A global configuration file can be found
in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/xdg/openbox&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, which is well documented, and copying the global
configuration to the user&apos;s directory will give a good starting point to start
customizing.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;cp&lt;/span&gt; -R /etc/xdg/openbox ~/.config/&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;These files can be edited by hand, although some graphical tools are also
available, use of these may be desired.&lt;/p&gt;
&lt;h1 id=&quot;themes-and-appearance&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#themes-and-appearance&quot;&gt;Themes and Appearance&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;obconf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;lxappearance-obconf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; can be used to configure appearance and theme
of openbox session. There are quite a few themes available in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;openbox-themes&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;
package. My personal favorite is &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Numix-themes&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Numix-icon-theme-git (AUR)&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;To see changes after editing a configuration file, the Openbox needs to be
refreshed. It can be done with the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;reconfigure&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; command.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;openbox&lt;/span&gt; --reconfigure&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;menus&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#menus&quot;&gt;Menus&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The type and behavior of Openbox menus, accessible by right-clicking the
background, can be changed using &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;~/.config/openbox/menu.xml&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file. Openbox
provides two kinds of menus, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Static&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Dynamic&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; menus (Piped and
Generators)&lt;/p&gt;
&lt;p&gt;Static menus are hardcoded in XML and is stored in the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;menu.xml&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file. Whenever
you install a new application, you will have to update the XML file to update
the menu manually. It is a viable solution if the apps are not installed on a
day to day basis.&lt;/p&gt;
&lt;p&gt;Pipe menus are the sections of the Openbox menu that Openbox creates on the fly
by running a generic script and using its plain text output as menu entries.
This scheme can be used in different ways, like adding a mail checker in the
menu or adding a weather forecast menu. You can check
&lt;a href=&quot;http://openbox.org/wiki/Openbox:Pipemenus&quot;&gt;openbox pipe menu page&lt;/a&gt; for more
information.&lt;/p&gt;
&lt;p&gt;Generators are the most convenient type of menus. These can be found in most
desktop environments where applications show up in the menu automatically. If
applications are being installed regularly, then this will probably be the
preferred choice.&lt;/p&gt;
&lt;h2 id=&quot;static-menus&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#static-menus&quot;&gt;Static Menus&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The process of making these menus can be automated by static menu generator like
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;obmenu&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. It will generate static menus from installed applications by looking
into certain directories. Others available tools are &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;menumaker&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;obmenu&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;xdg-menu&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;h2 id=&quot;dynamic-menus&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#dynamic-menus&quot;&gt;Dynamic Menus&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Dynamic menus give the same kind of functionality most people are used to. So it
was my preferred choice. They can be used to generate full, complex menus on the
fly. One of the most popular application for generating dynamic menus is
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;obmenu-generator&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. Though it is not officially connected to Openbox, it is
widely used.&lt;/p&gt;
&lt;p&gt;In order to have &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;obmenu-generator&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; make a menu on demand, the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;menu.xml&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file
should contain the following code as the only entry.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;&amp;#x3C;?&lt;/span&gt;xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;&amp;#x3C;&lt;/span&gt;openbox_menu&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;    &amp;#x3C;&lt;/span&gt;menu id=&quot;root-menu&quot; label=&quot;OpenBox 3&quot; execute=&quot;/usr/bin/obmenu-generator&quot;&gt;&amp;#x3C;/menu&gt;
&lt;span style=&quot;--shiki-dark:#F47067;--shiki-light:#D73A49&quot;&gt;&amp;#x3C;&lt;/span&gt;/openbox_menu&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;panels-and-taskbars&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#panels-and-taskbars&quot;&gt;Panels and Taskbars&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;You can get any panel like &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;xfce4-panel&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; or the simple and customizable &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;tint2&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.
I chose tint2 because it very closely follows the openbox spirit of having easy
customization with plain configuration files. tint2 package also containg a
graphical tool &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;tint2conf&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; for customizing panel and you can obviously go right
to the tint2 configuration file and edit it there. This also means it is easy to
pick up your configuration file and move it to another computer, or restore an
old configuration since it is as simple as pasting a text document in the right
place. tint2 can also have sections for each individual desktop and has various
small widget like programs that can be used with it such as a calendar,
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;gsimplecal&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, a volume application, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;volumeicon&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, a battery indicator,
&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;cbatticon&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;, a network indicator like &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;wicd&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; which also have a system tray icon
and a mini task tray. To start tint2 with openbox, you need to add &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;tint2 &amp;#x26;&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to
the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;autostart&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file.&lt;/p&gt;
&lt;h1 id=&quot;file-manager&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#file-manager&quot;&gt;File Manager&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Some file managers deeply integrate into desktop environments, and when
installed with Openbox, they end up pulling multiple dependencies, which is
certainly not desired. Our aim behind building an Openbox set up was to have
minimum dependencies so that we can get a lightweight desktop. However, there
are several file managers available that fit into the Openbox very well. In my
choice, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;pcmanfm&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; is the best choice here. pcmanfm is a lightweight and fast
file manager with network and thrash support. pcmanfm can also manage desktop
icons and wallpaper setting, although if you plan to use conky in your system,
then you may not want pcmanfm to manage desktop for you. The reason is that
pcmanfm treats desktop as a window, so when you switch to desktop, the conky
hides behind the desktop window. To get the icons and wallpaper, you can use
other standalone tools such as &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;idesk&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;feh&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; or &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;nitrogen&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. To start pcmanfm
is the desktop mode, add the following to the autostart file.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;pcmanfm&lt;/span&gt; --desktop &amp;#x26;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;and to stop it for managing desktop&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;pcmanfm&lt;/span&gt; --desktop-off &amp;#x26;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Many functions present in modern file managers require the installation of a few
additional programs. &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;gvfs&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; gives you the ability to mount volumes and have
trash control. It is not mandatory to have, but it allows on-demand &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;mounting&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;
completely from within the file manager, as opposed to having to drop down to
the command line. A disk-volume manager such as &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;udisks2&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; will also be wanted,
and for auto-mounting removable disks, &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;udiskie&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; works well with Openbox.
udiskie can be added to Openbox&apos;s autostart file like any other application.&lt;/p&gt;
&lt;h1 id=&quot;composition&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#composition&quot;&gt;Composition&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Openbox does not provide native support for composition, although having a
compositor may prevent screen flickering and other distortion in applications
like &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;oblogout&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. Some options work great with Openbox. The one which I am using
and quite happy with is &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;compton&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. It can be used with or without any initial
configuration, although there are a lot of different configuration options if
you decide to customize the setup. To start compton in background with shadows,
use this in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;autostart&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;compton&lt;/span&gt; -b -c &amp;#x26;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h1 id=&quot;wrapping-up&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#wrapping-up&quot;&gt;Wrapping up&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;While setting up my desktop using Openbox ended up being much more work than I
could have with typical desktop environments. But now I have a much more stable
desktop, about which I know, what is running in my system, and that my system is
not cluttered with any software that I never use.&lt;/p&gt;
&lt;p&gt;While it might not be for everybody having to configure every little bit of the
desktop, I genuinely feel I have ended up with excellent user experience, and a
system that is customized precisely to fit my needs.&lt;/p&gt;
&lt;h1 id=&quot;references&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#references&quot;&gt;References&lt;/a&gt;&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.archlinux.org/&quot;&gt;Arch Linux Wiki&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>A good Sublime Text setup</title><link>https://yashagarwal.in/notes/a-good-sublime-text-setup/</link><guid isPermaLink="true">https://yashagarwal.in/notes/a-good-sublime-text-setup/</guid><description>Optimize your Sublime Text editor setup with this guide, focusing on understanding configurations for a personalized and efficient development workflow.</description><pubDate>Thu, 14 Apr 2016 10:55:35 GMT</pubDate><content:encoded>&lt;p&gt;So, after a hectic day, good news finally came. I have been selected as a Lab
Administrator for the &lt;a href=&quot;https://www.facebook.com/sslnitc/&quot;&gt;Software Systems Lab&lt;/a&gt;
of my college. Cheers!!!&lt;/p&gt;
&lt;p&gt;Let&apos;s come to our today&apos;s topic on configuring Sublime Text Settings.&lt;/p&gt;
&lt;p&gt;There is just one rule you must follow while designing your own editor
preference configuration.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Don&apos;t put any lines in your configuration that you don&apos;t understand.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You will find tons of online tutorials that contains all kinds of awesome hacks
to make your sublime text experience better but the worst way to make your
development environment better is just to borrow the configuration from someone
else.&lt;/p&gt;
&lt;p&gt;Spending your time in actually understand what is happening behind the scenes in
the construction of your editor is immensely invaluable. It is similar to the
increased information retention that you experience when you copy something from
the board.&lt;/p&gt;
&lt;p&gt;So first, take some background of what we are going to do today. I am using
Sublime Text 3 – dev version, but most of the instructions are similar for
Sublime Text 2 also.&lt;/p&gt;
&lt;p&gt;Okay, first open the sublime text, then go to &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Preference → Settings → User&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;So this is your configuration file where you can put all your custom
preferences. There are other configuration files also, which can be found in
Preferences.&lt;/p&gt;
&lt;p&gt;You can also find all settings for reference in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Settings → Default&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file.&lt;/p&gt;
&lt;p&gt;Here is my &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Settings → User&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; file. Feel free to take inspiration from it, and
make your sublime text experience unmatchable. I have commented every setting
which is self-understandable.&lt;/p&gt;
&lt;p&gt;&lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;https://gist.github.com/yashhere/dea6728f88865666c20ff1c35e90bd0e&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;wrapping-it-up&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#wrapping-it-up&quot;&gt;Wrapping It Up&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I still stand by my platitude that&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Don&apos;t put anything in your configuration file you don&apos;t understand!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That&apos;s all for today. Thanks for reading.&lt;/p&gt;</content:encoded></item><item><title>Searching the goal</title><link>https://yashagarwal.in/notes/searching-the-goal/</link><guid isPermaLink="true">https://yashagarwal.in/notes/searching-the-goal/</guid><description>A reflective journey through a student&apos;s academic and career choices, highlighting the impact of external pressures on personal aspirations.</description><pubDate>Sun, 10 Apr 2016 00:33:16 GMT</pubDate><content:encoded>&lt;p&gt;A boy, probably of age 16, just cleared his 10th board exam. He saw people
working on computers, and that fascinated him. So he had only one ambition. You
got it, right? One fine day, suddenly his friend&apos;s mother asked, &quot;So what about
the future? You are going to enter in class 11th. It is the right time to decide
about your future. What do you want to become, a doctor or an engineer?&quot; The boy
had no clue how big that question was. What the cost would have been. He simply
nodded and said, &quot;I like computers very much so I would go for engineering.&quot;&lt;/p&gt;
&lt;p&gt;That&apos;s it. He decided his fate.&lt;/p&gt;
&lt;p&gt;So here comes the day&lt;/p&gt;
&lt;h1 id=&quot;an-accident&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#an-accident&quot;&gt;An accident&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;After that day, he got into a coaching institute which promised a good rank in
JEE. He was told that he would have to study consistently and regularly. The
boy, being a determined one, started studying day and night.&lt;/p&gt;
&lt;p&gt;This continued for two years. Finally, after giving 12th board exams, he gave
JEE. Unfortunately, he didn&apos;t even get into extended merit list.&lt;/p&gt;
&lt;p&gt;Devastated, he pledged not to give up. Oh, that stupid silly guy! He decided to
try for one more year.&lt;/p&gt;
&lt;p&gt;He joined another institute in his city. Again the same routine, studying day
and night to fulfill &lt;em&gt;his&lt;/em&gt; dreams.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Result&lt;/em&gt;: Same, Fail!&lt;/p&gt;
&lt;p&gt;But somehow he got a decent rank in JEE Mains thanks to his excellent
performance in board exams.&lt;/p&gt;
&lt;h1 id=&quot;a-disaster&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#a-disaster&quot;&gt;A disaster&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Now he had to face one more question. Which college and which branch? For him,
the answer was simple. Go to any South Indian college thanks to the influence of
his cousins on him (who were very successful in their lives, of course!). He
chose Computer Science and Engineering because&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;He loved computers.&lt;/li&gt;
&lt;li&gt;Everybody said, &quot;Bahut scope hai is branch me.&quot;&lt;/li&gt;
&lt;li&gt;Every top ranker of this country choose this branch.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So the decision was clear. He packed his bag and left home for a NIT situated
some 2200 kms far, the comp-sci branch.&lt;/p&gt;
&lt;h1 id=&quot;the-coding-disaster&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#the-coding-disaster&quot;&gt;The coding disaster&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;He reached the college. He loved new people, new place, new environment,
everything was new, right!. Studies started. He got good grades initially until
the real coding and Computer Science related stuff started as courses. His
grades fell drastically, his morale too. He got good marks enough to pass the
courses. He tried giving his best, but all concepts seemed so alien to him as
they wouldn&apos;t stay inside his head.&lt;/p&gt;
&lt;p&gt;That guy is now about to complete his 2nd year and just thinking what went wrong
with him. He is still trying to keep his journey on the right track. Whether he
will be able to finish it successfully or not, only time will tell.&lt;/p&gt;
&lt;p&gt;At last one more year is coming, and it&apos;s story will also come here next year.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.quora.com/What-were-you-once-that-youll-never-be-again/answer/Nishant-Kumar-187?srid=8MaF&amp;#x26;share=8df79cac&quot;&gt;Inspired by this Quora Post&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Wanna get insulted by sudo</title><link>https://yashagarwal.in/notes/wanna-get-insulted-by-sudo/</link><guid isPermaLink="true">https://yashagarwal.in/notes/wanna-get-insulted-by-sudo/</guid><description>Add a touch of humor to your Linux terminal! Learn how to enable hilarious insults from the `sudo` command on wrong password entries.</description><pubDate>Sun, 03 Apr 2016 12:20:36 GMT</pubDate><content:encoded>&lt;p&gt;You might have tried many Linux easters eggs for fun, but you are going to love
this hack which makes &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; insult you.&lt;/p&gt;
&lt;p&gt;Confused what I am talking about? Here, take a look at this gif to get an idea
of how &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; can insult you for typing in the incorrect password.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/insult.knTRXpmh_Z169WRU.webp&quot; alt=&quot;A terminal screen&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;814&quot; height=&quot;465&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now you might be thinking, why would anyone want to take insult? Afterall,
nobody likes being insulted. For me, it is just another way to have fun with
Linux, and anyway, this is way better than the plain &quot;You entered a wrong
password&quot; error message. So let&apos;s learn how to do this.&lt;/p&gt;
&lt;h1 id=&quot;enable-insults-in-sudo&quot;&gt;&lt;a href=&quot;https://yashagarwal.in/#enable-insults-in-sudo&quot;&gt;Enable insults in sudo&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;You can enable the insults feature in &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; by modifying the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;
configuration file. To open the &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; configuration file, launch a terminal and
type the following command.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; visudo&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;It will open &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;/etc/sudoers&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; configuration file in the terminal, in vim text
editor if you have configured it as your default editor. In distros like Ubuntu,
it will be opened in nano. Now you will have to find the section where the
defaults are listed. Most probably you will find it at the top. Now find the
line that starts with &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Defaults&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; and append the word &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;insults&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to the end of the
line (any addition to the line is comma separated). If this line is not present
then add the following line to the section&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;vim&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;vim&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#ADBAC7;--shiki-light:#24292E&quot;&gt;Defaults insults&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;(Always use &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;visudo&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; as it has a self-check system which will save you from
messing up things)&lt;/p&gt;
&lt;p&gt;Now save the file. If you are using vim, then use &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Ctrl+X&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to save the file and
quit the editor and if you are using nano then use &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Ctrl+X&lt;/span&gt;&lt;/code&gt;&lt;/span&gt; to leave the editor.
At the time of quitting, it will ask you if you want to save the changes. To
keep the changes, press &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;Y&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://yashagarwal.in/_astro/sudoers.BQe17_TY_Zvx2Aj.webp&quot; alt=&quot;Sample sudoers file&quot; title=&quot;Sample sudoers file&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1366&quot; height=&quot;740&quot;&gt;&lt;/p&gt;
&lt;p&gt;Once you have saved the file, go to terminal and type the following command to
clear the old password from &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;&apos;s cache.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;code data-language=&quot;bash&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span style=&quot;--shiki-dark:#F69D50;--shiki-light:#6F42C1&quot;&gt;sudo&lt;/span&gt; -k&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;That&apos;s all. Use any command with &lt;span data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;code data-language=&quot;plaintext&quot; data-theme=&quot;github-dark-dimmed github-light&quot;&gt;&lt;span&gt;sudo&lt;/span&gt;&lt;/code&gt;&lt;/span&gt;. Deliberately type a wrong password and
enjoy abusing …&lt;/p&gt;</content:encoded></item></channel></rss>