<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Abdul Talha</title>
    <description>The latest articles on DEV Community by Abdul Talha (@abdultalha08).</description>
    <link>https://dev.to/abdultalha08</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3021995%2Fc4c5b036-2fb7-41af-9841-513b507701f6.png</url>
      <title>DEV Community: Abdul Talha</title>
      <link>https://dev.to/abdultalha08</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/abdultalha08"/>
    <language>en</language>
    <item>
      <title>Instrument BookStack with OpenTelemetry and SigNoz Using Docker</title>
      <dc:creator>Abdul Talha</dc:creator>
      <pubDate>Sat, 18 Jul 2026 14:04:45 +0000</pubDate>
      <link>https://dev.to/abdultalha08/instrument-bookstack-with-opentelemetry-and-signoz-using-docker-2191</link>
      <guid>https://dev.to/abdultalha08/instrument-bookstack-with-opentelemetry-and-signoz-using-docker-2191</guid>
      <description>&lt;p&gt;Deploying BookStack was the easy part. Understanding what was happening inside the application wasn't. Without visibility into incoming requests, database queries, or Laravel operations, troubleshooting performance issues felt like guesswork. In this tutorial, you'll instrument BookStack with OpenTelemetry, connect it to SigNoz, and build an end-to-end observability pipeline, all without modifying the application's source code.&lt;/p&gt;

&lt;p&gt;BookStack is an open-source platform for creating and managing documentation, but it doesn't provide built-in distributed tracing or deep application observability. In this tutorial, you'll instrument BookStack with OpenTelemetry and export traces to SigNoz, enabling you to monitor requests, analyse Laravel application behaviour, and troubleshoot issues more effectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you begin, make sure you have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Linux server (Ubuntu 22.04 or later) with at least &lt;strong&gt;4 vCPUs&lt;/strong&gt; and &lt;strong&gt;8 GB RAM&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Docker Engine and Docker Compose are installed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Solution Overview
&lt;/h2&gt;

&lt;p&gt;BookStack is instrumented with OpenTelemetry, which exports traces to the OpenTelemetry Collector. The collector forwards the telemetry to SigNoz, where you can visualise requests and analyse distributed traces.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                HTTP Requests
                      │
                      ▼
               ┌─────────────┐
               │  BookStack  │
               │  (Laravel)  │
               └──────┬──────┘
                      │
          OpenTelemetry SDK
                      │
             OTLP (HTTP:4318)
                      │
                      ▼
        ┌────────────────────────┐
        │ OpenTelemetry Collector│
        │    (SigNoz Collector)  │
        └───────────┬────────────┘
                    │
                    ▼
              ┌───────────┐
              │  SigNoz   │
              │ Dashboard │
              └───────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 1: Install SigNoz
&lt;/h2&gt;

&lt;p&gt;Before instrumenting BookStack, you need a backend to collect, store, and visualise telemetry data. In this step, you'll install SigNoz using the &lt;code&gt;foundryctl&lt;/code&gt; CLI and verify that it's ready to receive traces from BookStack.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install the Foundry CLI, which simplifies deploying SigNoz by generating and managing the required Docker Compose configuration, and add it to your current PATH so the foundryctl command is available in your terminal.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://signoz.io/foundry.sh | bash
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/root/.local/bin:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Verify that the installation completed successfully:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;foundryctl version
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a file named &lt;code&gt;casting.yaml&lt;/code&gt; with the following configuration. This file instructs &lt;code&gt;foundryctl&lt;/code&gt; to deploy SigNoz using Docker Compose.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Installation&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;signoz&lt;/span&gt;

&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deployment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;flavor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;compose&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy SigNoz using the installation configuration.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;foundryctl cast &lt;span class="nt"&gt;-f&lt;/span&gt; casting.yaml
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The installer validates your Docker environment, generates the required Docker Compose resources, and starts the SigNoz services.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify that the deployment completed successfully.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;You should see containers such as &lt;code&gt;signoz-frontend&lt;/code&gt;, &lt;code&gt;signoz-query-service&lt;/code&gt;, &lt;code&gt;signoz-otel-collector&lt;/code&gt;, and &lt;code&gt;clickhouse&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then open &lt;code&gt;http://&amp;lt;SERVER-IP&amp;gt;:8080&lt;/code&gt; in your browser. If the installation completed successfully, the SigNoz dashboard should load. Replace &lt;code&gt;&amp;lt;SERVER-IP&amp;gt;&lt;/code&gt; with your Server IP.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo2r3i9y438bgskabghnt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo2r3i9y438bgskabghnt.png" alt=" " width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter the email and password to create the initial admin account for SigNoz.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5nvlkzrg5l6sc6ac3c8a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5nvlkzrg5l6sc6ac3c8a.png" alt=" " width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 2: Build a Custom BookStack Image
&lt;/h2&gt;

&lt;p&gt;The official LinuxServer BookStack image doesn't include the OpenTelemetry components required to export traces. In this step, you'll build a custom image that installs the OpenTelemetry PHP extension and Laravel auto-instrumentation packages during the image build, making the deployment reproducible and eliminating the need to modify a running container.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a project directory for the deployment and navigate into it.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;bookstack-otel
&lt;span class="nb"&gt;cd &lt;/span&gt;bookstack-otel
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Generate a Laravel application key. BookStack uses this key to encrypt sensitive application data, and you'll reference it later when creating the Docker Compose configuration.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"base64:&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rand &lt;span class="nt"&gt;-base64&lt;/span&gt; 32&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Save the generated value---you'll use it when configuring the BookStack container.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a file named &lt;code&gt;Dockerfile&lt;/code&gt; with the following configuration.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; lscr.io/linuxserver/bookstack:version-v26.03.3&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; install-opentelemetry.sh /tmp/install-opentelemetry.sh&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x /tmp/install-opentelemetry.sh &lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; /tmp/install-opentelemetry.sh &lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; /tmp/install-opentelemetry.sh &lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /root/.composer/cache

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app/www&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This Dockerfile extends the official BookStack image and runs the installation script during the image build.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a file named &lt;code&gt;install-opentelemetry.sh&lt;/code&gt; with the following installation script.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=========================================="&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Installing OpenTelemetry PHP Extension"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=========================================="&lt;/span&gt;

&lt;span class="c"&gt;# Add Alpine edge testing repository if missing&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s2"&gt;"edge/testing"&lt;/span&gt; /etc/apk/repositories&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"https://dl-cdn.alpinelinux.org/alpine/edge/testing"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /etc/apk/repositories
&lt;span class="k"&gt;fi

&lt;/span&gt;apk update

apk add &lt;span class="nt"&gt;--no-cache&lt;/span&gt; php85-pecl-opentelemetry

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=========================================="&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Installing OpenTelemetry Laravel Packages"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=========================================="&lt;/span&gt;

&lt;span class="nb"&gt;cd&lt;/span&gt; /app/www

composer config &lt;span class="nt"&gt;--no-interaction&lt;/span&gt; allow-plugins.php-http/discovery &lt;span class="nb"&gt;false
&lt;/span&gt;composer config &lt;span class="nt"&gt;--no-interaction&lt;/span&gt; allow-plugins.tbachert/spi &lt;span class="nb"&gt;true

&lt;/span&gt;composer require &lt;span class="se"&gt;\&lt;/span&gt;
    open-telemetry/sdk &lt;span class="se"&gt;\&lt;/span&gt;
    open-telemetry/exporter-otlp &lt;span class="se"&gt;\&lt;/span&gt;
    open-telemetry/opentelemetry-auto-laravel &lt;span class="se"&gt;\&lt;/span&gt;
    php-http/guzzle7-adapter &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--no-interaction&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--prefer-dist&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--optimize-autoloader&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--no-scripts&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=========================================="&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Verifying installation..."&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=========================================="&lt;/span&gt;

php &lt;span class="nt"&gt;-m&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;opentelemetry

composer show open-telemetry/sdk
composer show open-telemetry/opentelemetry-auto-laravel

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=========================================="&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"OpenTelemetry installation completed!"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=========================================="&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This script installs the OpenTelemetry PHP extension together with the Composer packages required for Laravel auto-instrumentation. It also performs basic validation during the image build to confirm that the required components were installed successfully.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 3: Deploy BookStack with OpenTelemetry
&lt;/h2&gt;

&lt;p&gt;With the custom image prepared, you're ready to deploy BookStack and its MariaDB database. In this step, you'll create a single Docker Compose configuration that builds the custom image, configures OpenTelemetry, and connects BookStack to the SigNoz OpenTelemetry Collector.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a &lt;code&gt;docker-compose.yml&lt;/code&gt; file with the following configuration.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;bookstack&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bookstack-otel:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bookstack&lt;/span&gt;

    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PUID=1000&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PGID=1000&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TZ=Asia/Kolkata&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;APP_URL=http://&amp;lt;SERVER-IP&amp;gt;:6875&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;APP_KEY=&amp;lt;APP_KEY&amp;gt;&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DB_HOST=bookstack_db&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DB_PORT=3306&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DB_DATABASE=bookstackapp&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DB_USERNAME=bookstack&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DB_PASSWORD=bookstack&lt;/span&gt;

      &lt;span class="c1"&gt;# OpenTelemetry&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OTEL_SERVICE_NAME=bookstack&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OTEL_TRACES_EXPORTER=otlp&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OTEL_METRICS_EXPORTER=none&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OTEL_LOGS_EXPORTER=none&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OTEL_EXPORTER_OTLP_ENDPOINT=http://signoz-ingester-1:4318&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OTEL_PHP_AUTOLOAD_ENABLED=true&lt;/span&gt;

    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./bookstack_data:/config&lt;/span&gt;

    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;6875:80"&lt;/span&gt;

    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bookstack_db&lt;/span&gt;

    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="na"&gt;bookstack_db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lscr.io/linuxserver/mariadb:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bookstack_db&lt;/span&gt;

    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PUID=1000&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PGID=1000&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;TZ=Asia/Kolkata&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MYSQL_ROOT_PASSWORD=&amp;lt;ROOT_PASSWORD&amp;gt;&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MYSQL_DATABASE=bookstackapp&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MYSQL_USER=bookstack&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MYSQL_PASSWORD=bookstack&lt;/span&gt;

    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./bookstack_db_data:/config&lt;/span&gt;

    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;signoz-network&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Replace:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;SERVER-IP&amp;gt;&lt;/code&gt; with your server's IP address or domain.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;APP_KEY&amp;gt;&lt;/code&gt; with the Laravel application key generated in the previous step.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;ROOT_PASSWORD&amp;gt;&lt;/code&gt; with a secure MariaDB root password.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;signoz-network&lt;/code&gt; with the Docker network created by your SigNoz installation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Build the custom image and start the BookStack and MariaDB containers.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Docker builds the custom BookStack image, installs the OpenTelemetry components, and starts both containers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify that the deployment completed successfully.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The &lt;code&gt;bookstack&lt;/code&gt; and &lt;code&gt;bookstack_db&lt;/code&gt; containers should both be in the &lt;strong&gt;Up&lt;/strong&gt; state.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open BookStack in your browser.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://&amp;lt;SERVER-IP&amp;gt;:6875
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Replace &lt;code&gt;&amp;lt;SERVER-IP&amp;gt;&lt;/code&gt; with your Server IP. The BookStack login page should load successfully, confirming that the application is running with the custom OpenTelemetry-enabled image. Enter email as &lt;code&gt;admin@admin.com&lt;/code&gt; and password as &lt;code&gt;password&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa1iarei1d7xnm2bvq8vf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa1iarei1d7xnm2bvq8vf.png" alt=" " width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6xif7h368bbr8rhszty9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6xif7h368bbr8rhszty9.png" alt=" " width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 4: Verify the OpenTelemetry Installation
&lt;/h2&gt;

&lt;p&gt;Before generating application traffic, verify that the OpenTelemetry components were installed correctly and that BookStack is configured to export traces. In this step, you'll confirm that the PHP extension, Composer packages, Laravel package discovery, and OpenTelemetry environment variables are all working as expected.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Verify that the OpenTelemetry PHP extension is loaded inside the BookStack container.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec &lt;/span&gt;bookstack php &lt;span class="nt"&gt;-m&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;opentelemetry
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;If the installation was successful, the command should return:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;opentelemetry
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Confirm that the required OpenTelemetry Composer packages were installed.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec &lt;/span&gt;bookstack composer show | &lt;span class="nb"&gt;grep &lt;/span&gt;opentelemetry
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;You should see packages similar to:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;open-telemetry/api
open-telemetry/sdk
open-telemetry/exporter-otlp
open-telemetry/opentelemetry-auto-laravel
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify that the OpenTelemetry environment variables are available inside the running container.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec &lt;/span&gt;bookstack &lt;span class="nb"&gt;printenv&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;OTEL
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;You should see output similar to:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OTEL_SERVICE_NAME=bookstack
OTEL_TRACES_EXPORTER=otlp
OTEL_EXPORTER_OTLP_ENDPOINT=http://signoz-ingester-1:4318
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_PHP_AUTOLOAD_ENABLED=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify that Laravel can discover the installed packages without errors.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec &lt;/span&gt;bookstack php artisan package:discover
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The command should complete successfully without reporting missing dependencies or package discovery errors.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open BookStack in your browser to confirm that the application is still running.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://&amp;lt;SERVER-IP&amp;gt;:6875
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Replace &lt;code&gt;&amp;lt;SERVER-IP&amp;gt;&lt;/code&gt; with your Server IP. The login page should load normally, confirming that the custom image is running correctly and is ready to export traces.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 5: Generate Application Traffic
&lt;/h2&gt;

&lt;p&gt;With BookStack configured and the OpenTelemetry installation verified, the next step is to generate application traffic. As users interact with BookStack, OpenTelemetry automatically captures each request and exports the resulting traces to the SigNoz OpenTelemetry Collector.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open BookStack in your browser.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://&amp;lt;SERVER-IP&amp;gt;:6875
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Replace &lt;code&gt;&amp;lt;SERVER-IP&amp;gt;&lt;/code&gt; with your Server IP.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Log in using the default BookStack administrator credentials or an existing user account.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generate application traffic by performing a few common actions in BookStack, such as:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Browse books and shelves.&lt;/li&gt;
&lt;li&gt;Open and view existing pages.&lt;/li&gt;
&lt;li&gt;Create a new page.&lt;/li&gt;
&lt;li&gt;Edit and save content.&lt;/li&gt;
&lt;li&gt;Navigate between different sections of the application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These actions generate HTTP requests that OpenTelemetry automatically instruments and exports to SigNoz.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: View Traces in SigNoz
&lt;/h2&gt;

&lt;p&gt;After generating application traffic, verify that BookStack is exporting traces to SigNoz. In this step, you'll inspect the collected traces and explore the request details captured by OpenTelemetry.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open the SigNoz dashboard in your browser.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://&amp;lt;SERVER-IP&amp;gt;:8080
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Replace &lt;code&gt;&amp;lt;SERVER-IP&amp;gt;&lt;/code&gt; with your Server IP.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;From the left navigation menu, select &lt;strong&gt;Traces&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click any trace from the &lt;strong&gt;bookstack&lt;/strong&gt; service to inspect its details.  The trace view displays the sequence of operations performed while processing a request. Depending on the action you performed, you'll typically see spans representing the incoming HTTP request, Laravel middleware, route handling, controller execution, and database operations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsf6qkfdcjsi9fodr7mvv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsf6qkfdcjsi9fodr7mvv.png" alt=" " width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Verify that the trace was recorded successfully. Confirm that:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Service Name&lt;/strong&gt; is &lt;code&gt;bookstack&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The trace completed successfully.&lt;/li&gt;
&lt;li&gt;Multiple spans are displayed for the request.&lt;/li&gt;
&lt;li&gt;The request duration and execution timeline are visible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Congratulations! You've successfully instrumented BookStack with OpenTelemetry and configured it to export traces to SigNoz. You now have end-to-end visibility into your application's requests, making it easier to understand application behaviour and troubleshoot performance issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Issues That I Encountered
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Docker and Docker Compose are not installed&lt;/strong&gt;: While deploying SigNoz with &lt;code&gt;foundryctl&lt;/code&gt;, the installation failed because Docker Engine and Docker Compose were not installed on the server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzchxrz9eiu1ugokrt0t3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzchxrz9eiu1ugokrt0t3.png" alt=" " width="798" height="111"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix&lt;/strong&gt;: Install Docker Engine and the Docker Compose plugin on your server. After the installation is complete, verify that both tools are available, then rerun the foundryctl cast command to continue the deployment.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;apt-transport-https ca-certificates curl software-properties-common &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;https://download.docker.com/linux/ubuntu/gpg]&lt;span class="o"&gt;(&lt;/span&gt;https://download.docker.com/linux/ubuntu/gpg&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /etc/apt/keyrings/docker.asc
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deb [arch=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;dpkg &lt;span class="nt"&gt;--print-architecture&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; signed-by=/etc/apt/keyrings/docker.asc] [https://download.docker.com/linux/ubuntu](https://download.docker.com/linux/ubuntu) &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; /etc/os-release &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$VERSION_CODENAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; stable"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/apt/sources.list.d/docker.list &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
&lt;span class="nb"&gt;sudo &lt;/span&gt;docker &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;docker
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status docker
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl stop docker
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;Building this setup highlighted a few practical lessons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use a custom Docker image.&lt;/strong&gt; Installing the OpenTelemetry components during the image build makes the deployment reproducible and prevents changes from being lost when containers are recreated.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Verify each step as you go.&lt;/strong&gt; Checking the PHP extension, Composer packages, and environment variables helped identify configuration issues early.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ensure the containers share the same network.&lt;/strong&gt; BookStack can only export traces if it can reach the SigNoz OpenTelemetry Collector.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Generate application traffic before checking SigNoz.&lt;/strong&gt; Traces are created only when BookStack processes requests.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You've successfully instrumented BookStack with OpenTelemetry and configured it to export traces to SigNoz, giving you end-to-end visibility into application requests with a reproducible Docker-based deployment.&lt;/p&gt;

&lt;p&gt;To continue exploring application observability, check out the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OpenTelemetry Documentation:&lt;/strong&gt; &lt;a href="https://opentelemetry.io/docs/" rel="noopener noreferrer"&gt;https://opentelemetry.io/docs/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SigNoz Documentation:&lt;/strong&gt; &lt;a href="https://signoz.io/docs/" rel="noopener noreferrer"&gt;https://signoz.io/docs/introduction/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SigNoz Distributed Tracing:&lt;/strong&gt; &lt;a href="https://signoz.io/docs/userguide/traces/" rel="noopener noreferrer"&gt;https://signoz.io/docs/userguide/traces/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>opensource</category>
      <category>docker</category>
      <category>laravel</category>
      <category>devops</category>
    </item>
    <item>
      <title>My Technical Writing Portfolio</title>
      <dc:creator>Abdul Talha</dc:creator>
      <pubDate>Tue, 07 Apr 2026 05:53:00 +0000</pubDate>
      <link>https://dev.to/abdultalha08/my-technical-writing-portfolio-54n2</link>
      <guid>https://dev.to/abdultalha08/my-technical-writing-portfolio-54n2</guid>
      <description>&lt;p&gt;I created a technical writing portfolio to organise the work I have been doing in documentation, tutorials, and open-source contributions.&lt;/p&gt;

&lt;p&gt;The goal was to bring together my writing in one place so developers and teams can easily explore my work.&lt;/p&gt;

&lt;p&gt;The portfolio includes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Articles published on freeCodeCamp&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tutorials on cloud deployments and developer tools&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Technical writing samples and guides&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Building this portfolio helped me reflect on the topics I enjoy writing about and the skills I want to continue improving.&lt;/p&gt;

&lt;p&gt;I plan to keep updating the portfolio as I publish new articles and contribute to more open-source projects.&lt;/p&gt;

&lt;p&gt;Portfolio: &lt;a href="https://blog.abdultalha.tech/portfolio" rel="noopener noreferrer"&gt;https://blog.abdultalha.tech/portfolio&lt;/a&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>documentation</category>
      <category>showdev</category>
      <category>writing</category>
    </item>
    <item>
      <title>How to Self-Host Affine on Windows Using Docker and WSL</title>
      <dc:creator>Abdul Talha</dc:creator>
      <pubDate>Tue, 31 Mar 2026 05:42:00 +0000</pubDate>
      <link>https://dev.to/abdultalha08/how-to-self-host-affine-on-windows-using-docker-and-wsl-176e</link>
      <guid>https://dev.to/abdultalha08/how-to-self-host-affine-on-windows-using-docker-and-wsl-176e</guid>
      <description>&lt;p&gt;I wrote a guide on how to self-host Affine on a Windows system using Docker and WSL.&lt;/p&gt;

&lt;p&gt;Affine is an open-source workspace that combines note-taking, documentation, and project management in one place. Running it locally allows developers to experiment with the platform and understand how self-hosted applications work.&lt;/p&gt;

&lt;p&gt;In this article, I walk through the full setup process for running Affine locally on Windows.&lt;/p&gt;

&lt;p&gt;The guide covers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Setting up Windows Subsystem for Linux (WSL)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Installing and configuring Docker&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Running Affine using Docker containers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Accessing the self-hosted instance locally&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The goal of this guide was to make the setup process simple and easy to follow for developers who want to explore self-hosting.&lt;/p&gt;

&lt;p&gt;The article was published on freeCodeCamp and went through their editorial review process. I learned a lot from the feedback and revisions during this process.&lt;/p&gt;

&lt;p&gt;You can read the full guide here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.freecodecamp.org/news/self-host-affine-on-windows-docker-wsl/" rel="noopener noreferrer"&gt;https://www.freecodecamp.org/news/self-host-affine-on-windows-docker-wsl/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>docker</category>
      <category>writing</category>
      <category>career</category>
    </item>
    <item>
      <title>My Documentation Contributions to Codecademy’s Open Source Repository</title>
      <dc:creator>Abdul Talha</dc:creator>
      <pubDate>Tue, 24 Mar 2026 05:58:00 +0000</pubDate>
      <link>https://dev.to/abdultalha08/my-documentation-contributions-to-codecademys-open-source-repository-nce</link>
      <guid>https://dev.to/abdultalha08/my-documentation-contributions-to-codecademys-open-source-repository-nce</guid>
      <description>&lt;p&gt;I contributed to the open-source documentation repository of Codecademy.&lt;/p&gt;

&lt;p&gt;During this work, I added five documentation entries while working through different issues in the repository. Each solu&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa7eezzc9vr4bmerfzixd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa7eezzc9vr4bmerfzixd.png" alt=" " width="800" height="369"&gt;&lt;/a&gt;tion was written in a separate branch in my fork so that the changes stayed organized.&lt;/p&gt;

&lt;p&gt;While working on these issues, I focused on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Understanding the structure of the documentation repository&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Writing clear explanations for the requested entries&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Following the contribution guidelines and workflow used by the project&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of the submissions passed the maintainer review process, which was a valuable learning experience.&lt;/p&gt;

&lt;p&gt;However, before the pull requests could be merged into the main repository, the project was made a public archive. Once a repository is archived, maintainers can no longer merge new contributions.&lt;/p&gt;

&lt;p&gt;Even though the changes were not merged into the main repository, the process helped me better understand how documentation contributions work in open-source projects.&lt;/p&gt;

&lt;p&gt;You can see the work in my forked repository, where each issue was solved in a separate branch.&lt;/p&gt;

&lt;p&gt;Repository:&lt;br&gt;
&lt;a href="https://github.com/abdultalha0862/docs" rel="noopener noreferrer"&gt;https://github.com/abdultalha0862/docs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>career</category>
      <category>technical</category>
      <category>writing</category>
    </item>
    <item>
      <title>How Open Source Can Grow Your Tech Career – A Handbook for Beginners</title>
      <dc:creator>Abdul Talha</dc:creator>
      <pubDate>Tue, 17 Mar 2026 05:02:00 +0000</pubDate>
      <link>https://dev.to/abdultalha08/how-open-source-can-grow-your-tech-career-a-handbook-for-beginners-544g</link>
      <guid>https://dev.to/abdultalha08/how-open-source-can-grow-your-tech-career-a-handbook-for-beginners-544g</guid>
      <description>&lt;p&gt;Many beginners have heard about open source but it may be confusing at first.&lt;/p&gt;

&lt;p&gt;When I first started learning programming, open source felt confusing. I didn’t clearly understand how projects worked or how contributing could help a developer grow.&lt;/p&gt;

&lt;p&gt;To make this easier for beginners, I wrote a handbook explaining how open source works and how developers can use it to grow their tech careers.&lt;/p&gt;

&lt;p&gt;In the handbook I covered topics like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;How open-source projects actually work&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The roles of maintainers, contributors, and communities&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Different ways beginners can contribute (not just code)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How open source builds skills, visibility, and career opportunities&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While writing this handbook, I also tried to explain the real challenges beginners face and how they can approach their first contribution step by step.&lt;/p&gt;

&lt;p&gt;This article went through the freeCodeCamp editorial review process, and I learned a lot from the feedback and revisions.&lt;/p&gt;

&lt;p&gt;If you're a beginner who wants to understand open source and start contributing, this guide may help you take the first step.&lt;/p&gt;

&lt;p&gt;Full handbook:&lt;br&gt;
&lt;a href="https://www.freecodecamp.org/news/open-source-career-handbook/" rel="noopener noreferrer"&gt;https://www.freecodecamp.org/news/open-source-career-handbook/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>career</category>
      <category>learning</category>
      <category>opensource</category>
    </item>
    <item>
      <title>From Ghost to Zulip: Setting Up Zulip Locally on WSL2 (and Fixing Tricky Python Issues)</title>
      <dc:creator>Abdul Talha</dc:creator>
      <pubDate>Thu, 18 Dec 2025 03:45:00 +0000</pubDate>
      <link>https://dev.to/abdultalha08/from-ghost-to-zulip-setting-up-zulip-locally-on-wsl2-and-fixing-tricky-python-issues-28kf</link>
      <guid>https://dev.to/abdultalha08/from-ghost-to-zulip-setting-up-zulip-locally-on-wsl2-and-fixing-tricky-python-issues-28kf</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;After contributing to &lt;strong&gt;Ghost&lt;/strong&gt;, I wanted to push myself further by working on a &lt;strong&gt;larger and more complex backend system&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That curiosity led me to &lt;strong&gt;Zulip&lt;/strong&gt;, an open-source team collaboration tool known for its topic-based threading and production-grade architecture.&lt;/p&gt;

&lt;p&gt;Zulip is built with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Django&lt;/li&gt;
&lt;li&gt;Tornado&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;RabbitMQ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Setting up Zulip locally isn’t hard, but it’s &lt;strong&gt;very different from a typical Django project&lt;/strong&gt;. I ran into a few unexpected issues, especially around Python virtual environments and WSL configuration.&lt;/p&gt;

&lt;p&gt;In this post, I’ll walk through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How I set up Zulip locally on WSL2&lt;/li&gt;
&lt;li&gt;The issues I faced during setup&lt;/li&gt;
&lt;li&gt;How I fixed them, including the &lt;code&gt;activate_this.py&lt;/code&gt; problem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re new to Zulip or moving into larger backend systems, this guide should help you avoid common setup blockers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who This Post Is For
&lt;/h2&gt;

&lt;p&gt;This post is for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developers contributing to &lt;strong&gt;Zulip&lt;/strong&gt; for the first time&lt;/li&gt;
&lt;li&gt;Open-source contributors moving beyond small projects&lt;/li&gt;
&lt;li&gt;Anyone using &lt;strong&gt;WSL2 on Windows&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Developers stuck with Python 3.12 or &lt;code&gt;activate_this.py&lt;/code&gt; errors&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting, make sure you have:&lt;/p&gt;

&lt;h3&gt;
  
  
  General
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;2GB+ RAM&lt;/li&gt;
&lt;li&gt;Stable internet connection&lt;/li&gt;
&lt;li&gt;GitHub account&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Windows
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Windows 10/11 (64-bit)&lt;/li&gt;
&lt;li&gt;Virtualisation enabled (VT-x / AMD-V)&lt;/li&gt;
&lt;li&gt;Admin access&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Git and GitHub Setup
&lt;/h2&gt;

&lt;p&gt;If Git is already configured, you can skip this section.&lt;/p&gt;

&lt;p&gt;Generate an SSH key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"your_email@example.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the public key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/id_ed25519.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add it to &lt;strong&gt;GitHub → Settings → SSH and GPG Keys&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up WSL2 for Zulip
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;If you already use native Ubuntu or WSL2, feel free to skip ahead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Enable Virtualisation
&lt;/h3&gt;

&lt;p&gt;Make sure VT-x / AMD-V is enabled in BIOS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install WSL2
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wsl &lt;span class="nt"&gt;--install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This installs Ubuntu automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enable systemd (Required)
&lt;/h3&gt;

&lt;p&gt;Zulip relies on background services like PostgreSQL, Redis, and RabbitMQ.&lt;/p&gt;

&lt;p&gt;Edit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/wsl.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[boot]&lt;/span&gt;
&lt;span class="py"&gt;systemd&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart WSL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wsl &lt;span class="nt"&gt;--shutdown&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install Required Services
&lt;/h2&gt;

&lt;p&gt;Update your system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;rabbitmq-server memcached redis-server postgresql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  RabbitMQ Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/rabbitmq/rabbitmq-env.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;NODE_IP_ADDRESS&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1&lt;/span&gt;
&lt;span class="py"&gt;NODE_PORT&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;5672&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cloning the Zulip Repository
&lt;/h2&gt;

&lt;p&gt;Fork Zulip from GitHub, then clone your fork:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;--config&lt;/span&gt; pull.rebase git@github.com:YOURUSERNAME/zulip.git
&lt;span class="nb"&gt;cd &lt;/span&gt;zulip
git remote add &lt;span class="nt"&gt;-f&lt;/span&gt; upstream https://github.com/zulip/zulip.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running Zulip Locally
&lt;/h2&gt;

&lt;p&gt;Install dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./tools/provision
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Activate the virtual environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start the dev server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./tools/run-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:9991
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Issues I Faced (and How I Fixed Them)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Issue 1: Missing &lt;code&gt;activate_this.py&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Error&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FileNotFoundError: No such file or directory ... activate_this.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this happens&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Zulip now uses &lt;strong&gt;uv&lt;/strong&gt;, which doesn’t automatically create &lt;code&gt;activate_this.py&lt;/code&gt;. Some scripts still expect it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Manually create the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .venv/bin/activate_this.py &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
import os
import site
import sys

bin_dir = os.path.dirname(os.path.abspath(__file__))
os.environ["PATH"] = os.pathsep.join([bin_dir] + os.environ.get("PATH", "").split(os.pathsep))

base = os.path.dirname(bin_dir)
os.environ["VIRTUAL_ENV"] = base

site_packages = os.path.join(base, 'lib', 'python{}.{}'.format(*sys.version_info[:2]), 'site-packages')

prev = set(sys.path)
site.addsitedir(site_packages)
sys.real_prefix = sys.prefix
sys.prefix = base

new = list(sys.path)
sys.path[:] = [i for i in new if i not in prev] + [i for i in new if i in prev]
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Issue 2: Django Not Found (Python 3.12)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Error&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ModuleNotFoundError: No module named 'django'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cause&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Older scripts used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This breaks with Python 3.12.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{}.{}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version_info&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then rerun:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./tools/provision
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Technical
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Modern Python tooling like &lt;code&gt;uv&lt;/code&gt; changes old assumptions&lt;/li&gt;
&lt;li&gt;Understanding virtual environments helps with debugging&lt;/li&gt;
&lt;li&gt;WSL2 + systemd setup is critical for backend services&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Non-Technical
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Large codebases require patience&lt;/li&gt;
&lt;li&gt;Error messages usually point to the real issue&lt;/li&gt;
&lt;li&gt;Open-source communities are incredibly helpful&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Moving from Ghost to Zulip has been a rewarding step in my open-source journey.&lt;/p&gt;

&lt;p&gt;Zulip’s setup may feel overwhelming at first, but once the environment is running, contributing becomes much smoother. If you’re stuck on setup issues like &lt;code&gt;activate_this.py&lt;/code&gt;, you’re definitely not alone.&lt;/p&gt;

&lt;p&gt;I hope this post helps you get unblocked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Zulip GitHub: &lt;a href="https://github.com/zulip/zulip" rel="noopener noreferrer"&gt;https://github.com/zulip/zulip&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Zulip Dev Docs: &lt;a href="https://zulip.readthedocs.io/en/latest/development/overview.html" rel="noopener noreferrer"&gt;https://zulip.readthedocs.io/en/latest/development/overview.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Zulip Community Chat: &lt;a href="https://chat.zulip.org" rel="noopener noreferrer"&gt;https://chat.zulip.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;WSL Docs: &lt;a href="https://docs.microsoft.com/en-us/windows/wsl" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/windows/wsl&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;uv: &lt;a href="https://github.com/astral-sh/uv" rel="noopener noreferrer"&gt;https://github.com/astral-sh/uv&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>opensource</category>
      <category>zulip</category>
      <category>python</category>
      <category>django</category>
    </item>
    <item>
      <title>My Journey into Open Source: Learning, Contributing, and Growing</title>
      <dc:creator>Abdul Talha</dc:creator>
      <pubDate>Mon, 04 Aug 2025 10:01:51 +0000</pubDate>
      <link>https://dev.to/abdultalha08/my-journey-into-open-source-learning-contributing-and-growing-3a1b</link>
      <guid>https://dev.to/abdultalha08/my-journey-into-open-source-learning-contributing-and-growing-3a1b</guid>
      <description>&lt;p&gt;I had no idea how to get started with Open Source until I watched a simple video by Kunal.&lt;/p&gt;

&lt;p&gt;Open Source is a fantastic way to develop software. Anyone, anywhere in the world, can see, use, and contribute to the code. It’s not just about writing code; it’s about collaborating to build something bigger.&lt;/p&gt;

&lt;p&gt;After watching Kunal's video (What is Open Source &amp;amp; How to Start?) and learning from Saviner Puri’s “Learn in Public” approach, I took a notebook and jotted down all the helpful insights they shared. I felt excited and eager to try those ideas.&lt;/p&gt;

&lt;p&gt;Then I faced a challenge: how do you select the right organization to contribute to? I felt overwhelmed and confused. This was my biggest obstacle.&lt;/p&gt;

&lt;p&gt;That’s when I discovered the Google Summer of Code (GSoC) website. Their filters help you find organizations matching your tech skills. After reviewing many options, I found Rocket.Chat, which was a perfect fit for my background.&lt;/p&gt;

&lt;p&gt;Throughout this journey, I learned some key lessons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Learn tools like Git and GitHub to contribute effectively.&lt;/li&gt;
&lt;li&gt;Choose contributions that align with your skills.&lt;/li&gt;
&lt;li&gt;Start small with beginner-friendly tasks to build your confidence.&lt;/li&gt;
&lt;li&gt;Above all, rely on the community and mentors; they make a significant difference.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Contributing to Open Source is not just about writing code. It involves working on real software, making connections that can lead to internships and jobs, leveraging your tech skills, and growing professionally. Sometimes, you might even get to speak at conferences or travel for events.&lt;/p&gt;

&lt;p&gt;If you already contribute, what’s your story? I’d love to hear from you. Please share your thoughts and any feedback in the comments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6v2i040cst3v2bkfp2h8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6v2i040cst3v2bkfp2h8.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>programming</category>
      <category>career</category>
    </item>
    <item>
      <title>Beginner's Guide to Mastering Git and GitHub</title>
      <dc:creator>Abdul Talha</dc:creator>
      <pubDate>Mon, 28 Apr 2025 14:53:46 +0000</pubDate>
      <link>https://dev.to/abdultalha08/beginners-guide-to-mastering-git-and-github-5063</link>
      <guid>https://dev.to/abdultalha08/beginners-guide-to-mastering-git-and-github-5063</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://blog.globalabdultalha.tech/beginners-guide-to-mastering-git-and-github" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;blog.globalabdultalha.tech / beginners-guide-to-mastering-git-and-github&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
      <category>discuss</category>
    </item>
    <item>
      <title>🚨 Perfecting My Web Layout (HTML + CSS + Semantic Tags) 🚨</title>
      <dc:creator>Abdul Talha</dc:creator>
      <pubDate>Mon, 14 Apr 2025 18:30:00 +0000</pubDate>
      <link>https://dev.to/abdultalha08/perfecting-my-web-layout-html-css-semantic-tags-3o0k</link>
      <guid>https://dev.to/abdultalha08/perfecting-my-web-layout-html-css-semantic-tags-3o0k</guid>
      <description>&lt;p&gt;&lt;strong&gt;The Struggle:&lt;/strong&gt; 💪😓&lt;br&gt;
I had an idea for a colorful and organized webpage layout, but my first design didn't match. The result was messy and unorganized, nothing like what I imagined!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Debugging&lt;/strong&gt; 🐞🔍🛠️:&lt;br&gt;&lt;br&gt;
1️⃣ Initial Insight:&lt;br&gt;&lt;br&gt;
I took a closer look at my code and realized I wasn't using any semantic tags. My layout was just a combination of divs, making the design difficult to control. &lt;/p&gt;

&lt;p&gt;2️⃣ Exploring Resources:&lt;br&gt;&lt;br&gt;
After watching a tutorial by CodeWithHarry on YouTube, I discovered that using semantic tags (like &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;, and &lt;code&gt;&amp;lt;footer&amp;gt;&lt;/code&gt;) not only makes the HTML more meaningful but also helps structure the layout more effectively. &lt;/p&gt;

&lt;p&gt;3️⃣ Breakthrough Moment:&lt;br&gt;&lt;br&gt;
I replaced my non-semantic tags with proper HTML5 elements, updated my CSS accordingly, and BOOM! My design transformed into exactly what I wanted. The improvement was night and day! &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson Learned:&lt;/strong&gt; 📚✨&lt;br&gt;
The moral of the story: Semantic tags bring both clarity and visual harmony to your web projects. They make your code more readable and your final design more polished. &lt;/p&gt;

&lt;p&gt;📸 &lt;strong&gt;Attached:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Comparison screenshots: the first image shows the final design, and the second image displays the initial messy layout.&lt;br&gt;&lt;br&gt;
🤔 To My Network:&lt;br&gt;&lt;br&gt;
Who else has realized this after using semantic tags? What were your takeaways?&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Farcr9f37bnjc0psv4rp8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Farcr9f37bnjc0psv4rp8.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxep8xx7hi0q9ryrfgieh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxep8xx7hi0q9ryrfgieh.png" alt="Image description" width="800" height="361"&gt;&lt;/a&gt; &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
      <category>learning</category>
    </item>
    <item>
      <title>🚨 From Chaos to Card Perfection (CSS Journey) 🚨</title>
      <dc:creator>Abdul Talha</dc:creator>
      <pubDate>Thu, 10 Apr 2025 15:37:00 +0000</pubDate>
      <link>https://dev.to/abdultalha08/from-chaos-to-card-perfection-css-journey-g0p</link>
      <guid>https://dev.to/abdultalha08/from-chaos-to-card-perfection-css-journey-g0p</guid>
      <description>&lt;p&gt;&lt;strong&gt;The Struggle:&lt;/strong&gt; &lt;br&gt;
At first, I threw all my content together into a card layout with no structure, using just plain text and images. It looked cluttered and unappealing. 😣 My initial design felt more like a rough draft than something polished.&lt;br&gt;
&lt;strong&gt;Debugging:&lt;/strong&gt;&lt;br&gt;
1️⃣ Initial Insight:&lt;br&gt;
I recognized that my card design lacked visual hierarchy and an appealing background. The layout needed a revamp to engage users truly.&lt;br&gt;
2️⃣ Exploring Resources:&lt;br&gt;
After watching a detailed video tutorial, I discovered the value of layering design elements. I learned that starting with a strong background and well-defined outer layers could transform the overall look of the card.&lt;br&gt;
3️⃣ Breakthrough Moment:&lt;br&gt;
I began by setting a contrasting body background color to highlight the card. Next, I defined the card’s outer layer to create a distinct container. Then, I added all the essential components and refined each element’s style. BOOM! The evolution from a messy draft to a sleek, professional card was complete!&lt;br&gt;
&lt;strong&gt;Lesson Learned:&lt;/strong&gt;&lt;br&gt;
 Moral of the story: A step-by-step approach to layering design elements can dramatically enhance your layout. Don't be afraid to start over and learn from tutorials—it's all part of the creative process.&lt;br&gt;
📸 Attached:&lt;br&gt;
I have attached the screenshots of both the initial and final card designs.&lt;br&gt;
🤔 To my network:&lt;br&gt;
 Who else has transformed their design by revisiting the fundamentals? What strategies did you use to upgrade your layouts?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhuvpd4pzas7ce9q5k869.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhuvpd4pzas7ce9q5k869.png" alt="Image description" width="566" height="857"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj3y2kt4frf8dv6fw46zk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj3y2kt4frf8dv6fw46zk.png" alt="Image description" width="496" height="779"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>learning</category>
      <category>programming</category>
    </item>
    <item>
      <title>🚨 From Chaos to Card perfection (CSS Journey) 🚨</title>
      <dc:creator>Abdul Talha</dc:creator>
      <pubDate>Thu, 10 Apr 2025 12:30:00 +0000</pubDate>
      <link>https://dev.to/abdultalha08/from-chaos-to-card-perfection-css-journey-3i8m</link>
      <guid>https://dev.to/abdultalha08/from-chaos-to-card-perfection-css-journey-3i8m</guid>
      <description>&lt;p&gt;&lt;strong&gt;The Struggle:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
At first, I threw all my content together into a card layout with no structure—just plain text and images. It looked cluttered and uninviting. 😣 My initial design felt more like a rough draft than something polished.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Debugging Saga:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
1️⃣ &lt;strong&gt;Initial Insight:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
I recognized that my card design was missing visual hierarchy and an appealing background. The layout needed a revamp to truly engage users.&lt;/p&gt;

&lt;p&gt;2️⃣ &lt;strong&gt;The Revelation:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
After watching a detailed video tutorial, I discovered the value of layering design elements. I learned that starting with a strong background and well-defined outer layers could transform the overall look of the card.&lt;/p&gt;

&lt;p&gt;3️⃣ &lt;strong&gt;Breakthrough Moment:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
I began by setting a contrasting body background color to highlight the card. Next, I defined the card’s outer layer to create a distinct container. Then, I added in all the essential components and refined each element’s style. BOOM—the evolution from a messy draft to a sleek, professional card was complete!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson Learned:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Moral of the story: A step-by-step approach to layering design elements can dramatically enhance your layout. Don't be afraid to start over and learn from tutorials—it's all part of the creative process.&lt;/p&gt;

&lt;p&gt;📸 &lt;strong&gt;Attached:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Side-by-side screenshots of the initial and final card designs
&lt;/li&gt;
&lt;li&gt;Code snippet illustrating key style improvements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🤔 &lt;strong&gt;To my network:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Who else has transformed their design by revisiting the fundamentals? What strategies did you use to upgrade your layouts?&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4mgdy112xcjod1hyxa3g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4mgdy112xcjod1hyxa3g.png" alt="Image description" width="566" height="857"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6rq8ug538pmj3okasho2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6rq8ug538pmj3okasho2.png" alt="Image description" width="496" height="779"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
      <category>learning</category>
    </item>
    <item>
      <title>The Open Source Lessons I’m Sharing to Empower Fellow Developers</title>
      <dc:creator>Abdul Talha</dc:creator>
      <pubDate>Wed, 09 Apr 2025 15:23:50 +0000</pubDate>
      <link>https://dev.to/abdultalha08/the-open-source-lessons-im-sharing-to-empower-fellow-developers-9</link>
      <guid>https://dev.to/abdultalha08/the-open-source-lessons-im-sharing-to-empower-fellow-developers-9</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/9v37uHRIAy0"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Approach Open Source Contribution Effectively
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Focus on Impact, Not Quantity&lt;/strong&gt;: Instead of measuring your contributions by the number of commits, prioritize meaningful fixes that deliver substantial value. Solving a critical issue effectively holds more weight than frequent, minor updates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start with the User Experience&lt;/strong&gt;:Before diving into the codebase, prioritize setting up the product locally. Address obstacles you encounter during installation or configuration—these pain points often reveal high-impact areas for contribution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Quality Over Frequency&lt;/strong&gt;: Rather than aiming for daily contributions, focus on solving one genuine, challenging problem. It’s acceptable—even beneficial—to invest time in resolving complex issues, as these efforts demonstrate deeper expertise and create lasting value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Document Your Journey&lt;/strong&gt;: Share your open source contributions publicly (e.g., LinkedIn, X/Twitter) to create a knowledge base. This helps others facing similar challenges while establishing your thought leadership and expanding your professional network.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Opportunities Unlocked by Open Source Contribution
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Career Advancement&lt;/strong&gt;: Open source contributions showcase technical skills and collaboration abilities, making you a stronger candidate for promotions, leadership roles, or high-impact projects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Freelancing/Consulting Opportunities&lt;/strong&gt;: Demonstrated expertise in specific tools or ecosystems through open source work can attract clients seeking specialized skills, often at premium rates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Global Recognition&lt;/strong&gt;: Consistent, valuable contributions position you as a subject matter expert, opening doors to speaking engagements, conference invitations, and collaborative projects with industry leaders.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>opensource</category>
      <category>beginners</category>
      <category>career</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
