<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[mirkenan's blog]]></title><description><![CDATA[mirkenan's blog]]></description><link>https://kenan7.com</link><generator>RSS for Node</generator><lastBuildDate>Tue, 19 May 2026 01:07:42 GMT</lastBuildDate><atom:link href="https://kenan7.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[The Ultimate Guide to LLM Observability Tools & Platforms (2025)]]></title><description><![CDATA[Large Language Models (LLMs) have taken the world by storm, powering everything from smart search engines to intelligent business automation. But as their use grows, so does the need to monitor, evaluate, and debug these complex AI systems in real ti...]]></description><link>https://kenan7.com/the-ultimate-guide-to-llm-observability-tools-and-platforms-2025</link><guid isPermaLink="true">https://kenan7.com/the-ultimate-guide-to-llm-observability-tools-and-platforms-2025</guid><category><![CDATA[llm]]></category><category><![CDATA[observability]]></category><category><![CDATA[AI]]></category><category><![CDATA[#ai-tools]]></category><dc:creator><![CDATA[Mirkenan Kazımzade]]></dc:creator><pubDate>Fri, 18 Jul 2025 17:36:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/UopUfxghnWo/upload/7cd6f1dc1f8179e812bf1b51faa8bd6e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Large Language Models (LLMs) have taken the world by storm, powering everything from smart search engines to intelligent business automation. But as their use grows, so does the need to <strong>monitor, evaluate, and debug</strong> these complex AI systems in real time. Welcome to the world of <strong>LLM observability</strong>!</p>
<p>In this post, I’ll walk you through the best LLM observability tools available today—including both <strong>open source projects</strong> and enterprise platforms—so you can keep your AI apps reliable, efficient, and compliant (and maybe even help you ace those SEO clicks).</p>
<h2 id="heading-what-is-llm-observability-and-why-does-it-matter">What is LLM Observability, and Why Does It Matter?</h2>
<p>LLM observability means <strong>tracking, evaluating, and improving</strong> how language models perform in the real world. Whether you’re building a chatbot, a content generator, or mission-critical automation, observability tools help answer questions such as:</p>
<ul>
<li><em>Why did my AI output something weird?</em></li>
<li><em>How much is this costing me?</em></li>
<li><em>Can I catch hallucinations before my users do?</em></li>
<li><em>Is my prompt engineering actually improving things?</em></li>
</ul>
<p>Without proper observability, issues like hallucinations, latency spikes, or costly inefficiencies go unnoticed—hurting both trust and the bottom line.</p>
<h2 id="heading-top-open-source-llm-observability-tools">Top Open Source LLM Observability Tools</h2>
<p>Love tinkering or want full control? Here’s a curated list of the <strong>best open source LLM observability platforms</strong> that you can host yourself or tweak for your needs:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Tool</td><td>License</td><td>Key Features</td></tr>
</thead>
<tbody>
<tr>
<td>Langfuse</td><td>Apache 2.0</td><td>Tracing, evaluations, prompt management, easy integrations</td></tr>
<tr>
<td>Phoenix (Arize)</td><td>Elastic 2.0</td><td>Tracing, hallucination evaluation, prompt mgmt, OpenTelemetry</td></tr>
<tr>
<td>Helicone</td><td>Apache 2.0</td><td>Monitoring, tracing, prompt playground, analytics</td></tr>
<tr>
<td>OpenLLMetry</td><td>Apache 2.0</td><td>OpenTelemetry tracing, works with LangChain, LlamaIndex, etc.</td></tr>
<tr>
<td>SigNoz</td><td>MIT</td><td>APM, custom tracing, LLM monitoring via OpenTelemetry</td></tr>
<tr>
<td>TruLens</td><td>MIT</td><td>LLM evals, quality assessment, prompt testing</td></tr>
<tr>
<td>PostHog</td><td>MIT</td><td>Analytics plus LLM monitoring, session replay</td></tr>
<tr>
<td>LangCheck</td><td>MIT</td><td>Quality metrics for LLMs (toxicity, relevance, etc.)</td></tr>
<tr>
<td>Literal AI</td><td>Custom OSS</td><td>Tracing, logging, human/LLM evals</td></tr>
<tr>
<td>Giskard AI</td><td>Apache 2.0</td><td>Explainability, model monitoring, LLM tracing</td></tr>
<tr>
<td>Langtrace.ai</td><td>MIT</td><td>Complete open source LLM tracing platform</td></tr>
<tr>
<td>OpenLIT</td><td>Apache 2.0</td><td>LLM metrics + Grafana dashboards</td></tr>
<tr>
<td>Opik</td><td>MIT</td><td>Prompt mgmt and tracing for LLM applications</td></tr>
<tr>
<td>Evidently AI</td><td>Apache 2.0</td><td>Model evals, explainability, LLM monitoring</td></tr>
</tbody>
</table>
</div><h2 id="heading-proprietary-amp-enterprise-llm-observability-platforms">Proprietary \&amp; Enterprise LLM Observability Platforms</h2>
<p>Prefer something more plug-and-play with official support? Check out these leading managed and commercial solutions:</p>
<ul>
<li><strong>Arize AI</strong> (Phoenix core): Unified monitoring, tracing, evaluation, supports most frameworks</li>
<li><strong>LangSmith</strong> (by LangChain): Deep observability for LangChain workflows</li>
<li><strong>Galileo AI</strong>: Real-time tracing and notification flows</li>
<li><strong>Datadog</strong>: Enterprise monitoring, new LLM features for OpenAI and LangChain users</li>
<li><strong>HoneyHive</strong>: End-to-end evals and monitoring</li>
<li><strong>Future AGI</strong>: Real-time anomaly detection, alerts, evaluation integrations</li>
<li><strong>Weights \&amp; Biases (Weave)</strong>: LLM pipeline tracing, prompt logs, metrics</li>
</ul>
<blockquote>
<p><strong>Tip:</strong> Many of these vendors offer free or community tiers if you’re just experimenting.</p>
</blockquote>
<h2 id="heading-specialized-amp-niche-tools-worth-knowing">Specialized \&amp; Niche Tools Worth Knowing</h2>
<ul>
<li><strong>AgentOps, CrewAI:</strong> Multi-agent tracing for complex workflow apps (mix of open and closed source)</li>
<li><strong>MLflow:</strong> Traditional ML monitoring, with new LLM add-ons</li>
<li><strong>DeepEval, Confident AI:</strong> LLM quality testing and evaluation</li>
<li><strong>Aporia, WhyLabs, LangKit:</strong> General ML observability tools now supporting LLM workflows</li>
<li><strong>LlamaIndex Observability:</strong> Built-in tools for RAG and document Q\&amp;A frameworks</li>
</ul>
<h2 id="heading-quick-comparison-table-open-source-leaders">Quick Comparison Table: Open Source Leaders</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Name</td><td>Github Stars (2025)</td><td>License</td><td>Integrations</td><td>Tracing</td><td>LLM Evals</td></tr>
</thead>
<tbody>
<tr>
<td>Langfuse</td><td>5k+</td><td>Apache 2.0</td><td>LangChain, LlamaIndex</td><td>Yes</td><td>Yes</td></tr>
<tr>
<td>Phoenix</td><td>5k+</td><td>Elastic 2.0</td><td>LangChain, LlamaIndex, etc.</td><td>Yes</td><td>Yes</td></tr>
<tr>
<td>Helicone</td><td>3k+</td><td>Apache 2.0</td><td>OpenAI, Anthropic, etc.</td><td>Yes</td><td>Yes</td></tr>
<tr>
<td>OpenLLMetry</td><td>3k+</td><td>Apache 2.0</td><td>Supports 10+ backends</td><td>Yes</td><td>No</td></tr>
<tr>
<td>PostHog</td><td>26k+</td><td>MIT</td><td>Multi-framework</td><td>Yes</td><td>Yes</td></tr>
<tr>
<td>SigNoz</td><td>15k+</td><td>MIT</td><td>Any (via OpenTelemetry)</td><td>Yes</td><td>No</td></tr>
</tbody>
</table>
</div><h2 id="heading-key-features-to-watch-for">Key Features to Watch For</h2>
<ul>
<li><strong>Tracing:</strong> Visualize request/response flows, spot bottlenecks.</li>
<li><strong>Prompt Management:</strong> Version control, A/B testing, and playgrounds.</li>
<li><strong>Evaluations:</strong> Automated and human-in-the-loop scoring for quality, relevance, hallucinations, etc.</li>
<li><strong>Cost/Token Monitoring:</strong> Track cost and token usage to rein in experiment budgets.</li>
<li><strong>Framework Integrations:</strong> Plug into your existing LangChain, LlamaIndex, or RAG stack.</li>
<li><strong>Self-Hosting:</strong> Most open source tools support on-prem installs—crucial for sensitive data!</li>
</ul>
<h2 id="heading-final-thoughts-choosing-the-best-tool-for-your-needs">Final Thoughts: Choosing the Best Tool for Your Needs</h2>
<p>The right LLM observability stack depends on what you’re building:</p>
<ul>
<li><strong>OpenLatency tools</strong> (like OpenLLMetry, SigNoz) are perfect for enterprises running Kubernetes or with established observability pipelines.</li>
<li><strong>Self-hosters and startups</strong> should check out Langfuse, Helicone, or PostHog for robust features at zero cost.</li>
<li><strong>Production teams</strong> needing support or deep evals might benefit from LangSmith or Arize AI.</li>
</ul>
<p>With the LLM tooling ecosystem growing rapidly, there’s never been a better time to experiment, <strong>ship faster</strong>, and keep your users—and your CFO—happy.</p>
<p><em>Got a favorite LLM observability tool I missed? Drop a comment or send a tweet—let’s keep this guide up to date!</em></p>
]]></content:encoded></item><item><title><![CDATA[Understanding Dependency Injection in Go: A Practical Guide]]></title><description><![CDATA[Have you ever had your code become too tightly coupled, making it hard to test and maintain? Some people certainly have. Let me share a story about how dependency injection would help you write better, more maintainable Go code.
The Problem: A Coffee...]]></description><link>https://kenan7.com/understanding-dependency-injection-in-go-a-practical-guide</link><guid isPermaLink="true">https://kenan7.com/understanding-dependency-injection-in-go-a-practical-guide</guid><category><![CDATA[golang]]></category><category><![CDATA[dependency injection]]></category><category><![CDATA[dependency management]]></category><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[software architecture]]></category><dc:creator><![CDATA[Mirkenan Kazımzade]]></dc:creator><pubDate>Tue, 18 Feb 2025 22:15:22 GMT</pubDate><content:encoded><![CDATA[<p>Have you ever had your code become too tightly coupled, making it hard to test and maintain? Some people certainly have. Let me share a story about how dependency injection would help you write better, more maintainable Go code.</p>
<h2 id="heading-the-problem-a-coffee-machine-gone-wrong">The Problem: A Coffee Machine Gone Wrong</h2>
<p>Let's start with a real-world analogy. Imagine you're building a coffee machine program. Here's how you might initially write it:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> CoffeeMachine <span class="hljs-keyword">struct</span> {
    grinder *Grinder
    heater  *Heater
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewCoffeeMachine</span><span class="hljs-params">()</span> *<span class="hljs-title">CoffeeMachine</span></span> {
    <span class="hljs-keyword">return</span> &amp;CoffeeMachine{
        grinder: NewGrinder(),
        heater:  NewHeater(),
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(c *CoffeeMachine)</span> <span class="hljs-title">BrewCoffee</span><span class="hljs-params">()</span> <span class="hljs-title">string</span></span> {
    c.grinder.Grind()
    c.heater.Heat()
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Your coffee is ready!"</span>
}
</code></pre>
<p>What's wrong with this code? The <code>CoffeeMachine</code> is creating its own dependencies (grinder and heater). It's like buying a coffee machine where the grinder and heater are permanently welded inside. If either breaks, you'd have to replace the entire machine!</p>
<h2 id="heading-enter-dependency-injection">Enter Dependency Injection</h2>
<p>Dependency injection is like making a modular coffee machine where you can easily swap out components. Here's how we can improve our code:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Grinder <span class="hljs-keyword">interface</span> {
    Grind() <span class="hljs-keyword">string</span>
}

<span class="hljs-keyword">type</span> Heater <span class="hljs-keyword">interface</span> {
    Heat() <span class="hljs-keyword">string</span>
}

<span class="hljs-keyword">type</span> CoffeeMachine <span class="hljs-keyword">struct</span> {
    grinder Grinder
    heater  Heater
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewCoffeeMachine</span><span class="hljs-params">(g Grinder, h Heater)</span> *<span class="hljs-title">CoffeeMachine</span></span> {
    <span class="hljs-keyword">return</span> &amp;CoffeeMachine{
        grinder: g,
        heater:  h,
    }
}
</code></pre>
<p>Now we're passing the dependencies through the constructor. This is dependency injection in its simplest form!</p>
<h2 id="heading-why-this-matters-testing-made-easy">Why This Matters: Testing Made Easy</h2>
<p>Let's say we want to test our coffee machine. With the first approach, we'd need real grinder and heater components. But with dependency injection, we can create mock components:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> MockGrinder <span class="hljs-keyword">struct</span>{}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(m *MockGrinder)</span> <span class="hljs-title">Grind</span><span class="hljs-params">()</span> <span class="hljs-title">string</span></span> { <span class="hljs-keyword">return</span> <span class="hljs-string">"Mock grinding"</span> }

<span class="hljs-keyword">type</span> MockHeater <span class="hljs-keyword">struct</span>{}
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(m *MockHeater)</span> <span class="hljs-title">Heat</span><span class="hljs-params">()</span> <span class="hljs-title">string</span></span> { <span class="hljs-keyword">return</span> <span class="hljs-string">"Mock heating"</span> }

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">TestCoffeeMachine</span><span class="hljs-params">(t *testing.T)</span></span> {
    mockGrinder := &amp;MockGrinder{}
    mockHeater := &amp;MockHeater{}

    machine := NewCoffeeMachine(mockGrinder, mockHeater)
    result := machine.BrewCoffee()

    <span class="hljs-keyword">if</span> result != <span class="hljs-string">"Your coffee is ready!"</span> {
        t.Error(<span class="hljs-string">"Expected coffee to be ready"</span>)
    }
}
</code></pre>
<h2 id="heading-a-more-real-world-example-user-service">A More Real-World Example: User Service</h2>
<p>Let's look at a more practical example - a user service that needs to interact with a database and send emails:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> UserService <span class="hljs-keyword">struct</span> {
    db    Database
    mailer EmailService
    logger Logger
}

<span class="hljs-keyword">type</span> Database <span class="hljs-keyword">interface</span> {
    SaveUser(user User) error
    GetUser(id <span class="hljs-keyword">string</span>) (User, error)
}

<span class="hljs-keyword">type</span> EmailService <span class="hljs-keyword">interface</span> {
    SendWelcomeEmail(user User) error
}

<span class="hljs-keyword">type</span> Logger <span class="hljs-keyword">interface</span> {
    Log(message <span class="hljs-keyword">string</span>)
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewUserService</span><span class="hljs-params">(db Database, mailer EmailService, logger Logger)</span> *<span class="hljs-title">UserService</span></span> {
    <span class="hljs-keyword">return</span> &amp;UserService{
        db:     db,
        mailer: mailer,
        logger: logger,
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(s *UserService)</span> <span class="hljs-title">CreateUser</span><span class="hljs-params">(user User)</span> <span class="hljs-title">error</span></span> {
    s.logger.Log(<span class="hljs-string">"Creating new user"</span>)

    <span class="hljs-keyword">if</span> err := s.db.SaveUser(user); err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }

    <span class="hljs-keyword">if</span> err := s.mailer.SendWelcomeEmail(user); err != <span class="hljs-literal">nil</span> {
        s.logger.Log(<span class="hljs-string">"Failed to send welcome email"</span>)
        <span class="hljs-keyword">return</span> err
    }

    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
}
</code></pre>
<h2 id="heading-using-the-service">Using the Service</h2>
<p>Here's how you might use this service in your application:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    db := postgres.NewConnection()
    mailer := smtp.NewEmailService()
    logger := zap.NewLogger()

    userService := NewUserService(db, mailer, logger)

    user := User{
        ID:    <span class="hljs-string">"1"</span>,
        Email: <span class="hljs-string">"john@example.com"</span>,
        Name:  <span class="hljs-string">"John Doe"</span>,
    }

    err := userService.CreateUser(user)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatal(err)
    }
}
</code></pre>
<h2 id="heading-benefits-of-this-approach">Benefits of This Approach</h2>
<ol>
<li><strong>Testability</strong>: You can easily create mock implementations for testing.</li>
<li><strong>Flexibility</strong>: You can swap implementations without changing the service code.</li>
<li><strong>Separation of Concerns</strong>: Each component has a single responsibility.</li>
<li><strong>Maintainability</strong>: Dependencies are explicit and visible.</li>
</ol>
<h2 id="heading-common-patterns-and-best-practices">Common Patterns and Best Practices</h2>
<ol>
<li><strong>Use Interfaces</strong>: Define interfaces for your dependencies instead of concrete types.</li>
<li><strong>Constructor Injection</strong>: Pass dependencies through constructors rather than setting them after creation.</li>
<li><strong>Keep Dependencies Minimal</strong>: Only inject what you need.</li>
<li><strong>Use Functional Options</strong>: For optional dependencies or configuration.</li>
</ol>
<p>Here's an example of functional options:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> UserServiceOption <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(*UserService)</span></span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">WithLogger</span><span class="hljs-params">(logger Logger)</span> <span class="hljs-title">UserServiceOption</span></span> {
    <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(s *UserService)</span></span> {
        s.logger = logger
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewUserService</span><span class="hljs-params">(db Database, mailer EmailService, opts ...UserServiceOption)</span> *<span class="hljs-title">UserService</span></span> {
    s := &amp;UserService{
        db:     db,
        mailer: mailer,
        logger: defaultLogger{}, <span class="hljs-comment">// Default implementation</span>
    }

    <span class="hljs-keyword">for</span> _, opt := <span class="hljs-keyword">range</span> opts {
        opt(s)
    }

    <span class="hljs-keyword">return</span> s
}
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Dependency injection might seem like extra work at first, but it pays off in the long run. It makes your code more testable, maintainable, and flexible. Think of it as building with LEGO blocks instead of carving from a single piece of wood - you can always rearrange the pieces as needed.</p>
<p>Remember:</p>
<ul>
<li>Start with interfaces</li>
<li>Inject dependencies through constructors</li>
<li>Keep your components loosely coupled</li>
<li>Think about testing from the start</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Understanding Domain-Driven Design (DDD) with Go: A Practical Guide]]></title><description><![CDATA[Domain-Driven Design (DDD) is an approach to software development that focuses on understanding and modeling the business domain. In this post, we'll explore how to implement DDD principles using Go, with practical examples and clear explanations.
Wh...]]></description><link>https://kenan7.com/understanding-domain-driven-design-ddd-with-go-a-practical-guide</link><guid isPermaLink="true">https://kenan7.com/understanding-domain-driven-design-ddd-with-go-a-practical-guide</guid><category><![CDATA[Go Language]]></category><category><![CDATA[golang]]></category><category><![CDATA[#Domain-Driven-Design]]></category><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[software architecture]]></category><dc:creator><![CDATA[Mirkenan Kazımzade]]></dc:creator><pubDate>Tue, 18 Feb 2025 18:32:21 GMT</pubDate><content:encoded><![CDATA[<p>Domain-Driven Design (DDD) is an approach to software development that focuses on understanding and modeling the business domain. In this post, we'll explore how to implement DDD principles using Go, with practical examples and clear explanations.</p>
<h2 id="heading-what-is-domain-driven-design">What is Domain-Driven Design?</h2>
<p>DDD is a methodology that emphasizes:</p>
<ul>
<li>Close collaboration between technical and domain experts</li>
<li>Creating a shared understanding of the business domain</li>
<li>Building software that reflects the business model</li>
</ul>
<h2 id="heading-key-building-blocks-of-ddd-in-go">Key Building Blocks of DDD in Go</h2>
<h3 id="heading-1-value-objects">1. Value Objects</h3>
<p>Value Objects are immutable objects that have no identity. They are defined by their attributes.</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Money <span class="hljs-keyword">struct</span> {
    amount   decimal.Decimal
    currency <span class="hljs-keyword">string</span>
}

<span class="hljs-comment">// Constructor ensures immutability</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewMoney</span><span class="hljs-params">(amount decimal.Decimal, currency <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">Money</span></span> {
    <span class="hljs-keyword">return</span> Money{
        amount:   amount,
        currency: currency,
    }
}

<span class="hljs-comment">// Value objects should be comparable</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(m Money)</span> <span class="hljs-title">Equals</span><span class="hljs-params">(other Money)</span> <span class="hljs-title">bool</span></span> {
    <span class="hljs-keyword">return</span> m.amount.Equals(other.amount) &amp;&amp; m.currency == other.currency
}
</code></pre>
<h3 id="heading-2-entities">2. Entities</h3>
<p>Entities are objects with a unique identity that persists throughout their lifecycle.</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> Order <span class="hljs-keyword">struct</span> {
    ID          <span class="hljs-keyword">string</span>
    CustomerID  <span class="hljs-keyword">string</span>
    Items       []OrderItem
    TotalAmount Money
    Status      OrderStatus
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewOrder</span><span class="hljs-params">(id <span class="hljs-keyword">string</span>, customerID <span class="hljs-keyword">string</span>)</span> *<span class="hljs-title">Order</span></span> {
    <span class="hljs-keyword">return</span> &amp;Order{
        ID:         id,
        CustomerID: customerID,
        Items:      <span class="hljs-built_in">make</span>([]OrderItem, <span class="hljs-number">0</span>),
        Status:     OrderStatusPending,
    }
}
</code></pre>
<h3 id="heading-3-aggregates">3. Aggregates</h3>
<p>Aggregates are clusters of related entities and value objects treated as a single unit.</p>
<pre><code class="lang-go"><span class="hljs-comment">// Order is the aggregate root</span>
<span class="hljs-keyword">type</span> Order <span class="hljs-keyword">struct</span> {
    <span class="hljs-comment">// ... previous fields ...</span>

    <span class="hljs-comment">// Methods to maintain invariants</span>
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(o *Order)</span> <span class="hljs-title">AddItem</span><span class="hljs-params">(item OrderItem)</span> <span class="hljs-title">error</span></span> {
        <span class="hljs-keyword">if</span> o.Status != OrderStatusPending {
            <span class="hljs-keyword">return</span> errors.New(<span class="hljs-string">"cannot add items to non-pending order"</span>)
        }
        o.Items = <span class="hljs-built_in">append</span>(o.Items, item)
        o.recalculateTotal()
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(o *Order)</span> <span class="hljs-title">recalculateTotal</span><span class="hljs-params">()</span></span> {
        <span class="hljs-comment">// Logic to calculate total</span>
    }
}
</code></pre>
<h3 id="heading-4-repositories">4. Repositories</h3>
<p>Repositories handle persistence of aggregates.</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> OrderRepository <span class="hljs-keyword">interface</span> {
    Save(ctx context.Context, order *Order) error
    FindByID(ctx context.Context, id <span class="hljs-keyword">string</span>) (*Order, error)
    FindByCustomer(ctx context.Context, customerID <span class="hljs-keyword">string</span>) ([]*Order, error)
}

<span class="hljs-comment">// Implementation example</span>
<span class="hljs-keyword">type</span> PostgresOrderRepository <span class="hljs-keyword">struct</span> {
    db *sql.DB
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(r *PostgresOrderRepository)</span> <span class="hljs-title">Save</span><span class="hljs-params">(ctx context.Context, order *Order)</span> <span class="hljs-title">error</span></span> {
    <span class="hljs-comment">// Implementation details</span>
}
</code></pre>
<h3 id="heading-5-domain-services">5. Domain Services</h3>
<p>Domain Services handle operations that don't naturally fit within entities or value objects.</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> OrderProcessor <span class="hljs-keyword">interface</span> {
    ProcessOrder(ctx context.Context, order *Order) error
}

<span class="hljs-keyword">type</span> OrderProcessorService <span class="hljs-keyword">struct</span> {
    orderRepo      OrderRepository
    paymentService PaymentService
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(s *OrderProcessorService)</span> <span class="hljs-title">ProcessOrder</span><span class="hljs-params">(ctx context.Context, order *Order)</span> <span class="hljs-title">error</span></span> {
    <span class="hljs-comment">// Complex business logic involving multiple aggregates</span>
}
</code></pre>
<h2 id="heading-organizing-your-go-project-with-ddd">Organizing Your Go Project with DDD</h2>
<p>Here's a typical project structure following DDD principles:</p>
<pre><code>├── cmd/
│   └── api/
│       └── main.go
├── internal/
│   ├── domain/
│   │   ├── order.go        <span class="hljs-comment">// Entities and Value Objects</span>
│   │   ├── customer.go
│   │   └── money.go
│   ├── repository/
│   │   └── order.go        <span class="hljs-comment">// Repository implementations</span>
│   ├── service/
│   │   └── order.go        <span class="hljs-comment">// Domain Services</span>
│   └── application/
│       └── orderservice.go  <span class="hljs-comment">// Application Services</span>
└── pkg/
    └── shared/             <span class="hljs-comment">// Shared kernel</span>
</code></pre><h2 id="heading-best-practices">Best Practices</h2>
<ol>
<li><strong>Use Interfaces</strong>: Define clear boundaries between layers using interfaces.</li>
</ol>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> OrderService <span class="hljs-keyword">interface</span> {
    CreateOrder(ctx context.Context, customerID <span class="hljs-keyword">string</span>) (*Order, error)
    AddItem(ctx context.Context, orderID <span class="hljs-keyword">string</span>, item OrderItem) error
}
</code></pre>
<ol start="2">
<li><strong>Implement Validation</strong>: Use value objects to ensure data validity.</li>
</ol>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">NewEmail</span><span class="hljs-params">(address <span class="hljs-keyword">string</span>)</span> <span class="hljs-params">(Email, error)</span></span> {
    <span class="hljs-keyword">if</span> !isValidEmail(address) {
        <span class="hljs-keyword">return</span> Email{}, errors.New(<span class="hljs-string">"invalid email address"</span>)
    }
    <span class="hljs-keyword">return</span> Email{address: address}, <span class="hljs-literal">nil</span>
}
</code></pre>
<ol start="3">
<li><strong>Handle Errors</strong>: Create domain-specific errors.</li>
</ol>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> DomainError <span class="hljs-keyword">struct</span> {
    Message <span class="hljs-keyword">string</span>
    Code    <span class="hljs-keyword">string</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(e *DomainError)</span> <span class="hljs-title">Error</span><span class="hljs-params">()</span> <span class="hljs-title">string</span></span> {
    <span class="hljs-keyword">return</span> e.Message
}

<span class="hljs-keyword">var</span> ErrInvalidOrderStatus = &amp;DomainError{
    Message: <span class="hljs-string">"invalid order status"</span>,
    Code:    <span class="hljs-string">"INVALID_ORDER_STATUS"</span>,
}
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>DDD in Go helps create maintainable and scalable applications by:</p>
<ul>
<li>Separating concerns through clear boundaries</li>
<li>Enforcing business rules at the domain level</li>
<li>Creating a shared understanding between technical and domain experts</li>
</ul>
<p>Remember that DDD is not about the code structure alone - it's about understanding and modeling the business domain effectively. The Go programming language, with its simplicity and strong typing, provides an excellent foundation for implementing DDD principles.</p>
<p>This is just an introduction to DDD in Go. As you dive deeper, you'll discover more patterns and practices that can help you build better domain-driven applications.</p>
]]></content:encoded></item><item><title><![CDATA[Achieving Symmetrical ManyToMany Filtering in Django Admin]]></title><description><![CDATA[I recently tackled an interesting challenge that I think could benefit others in the community. The problem? Creating a symmetrical ManyToMany filter widget in the Django admin dashboard. You know, the kind where you can filter and select related obj...]]></description><link>https://kenan7.com/achieving-symmetrical-manytomany-filtering-in-django-admin</link><guid isPermaLink="true">https://kenan7.com/achieving-symmetrical-manytomany-filtering-in-django-admin</guid><category><![CDATA[Django]]></category><category><![CDATA[many to many]]></category><category><![CDATA[django admin]]></category><category><![CDATA[django forms]]></category><category><![CDATA[Python]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[Databases]]></category><category><![CDATA[backend]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Mirkenan Kazımzade]]></dc:creator><pubDate>Thu, 24 Oct 2024 20:21:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/KdjO4qoBb3E/upload/63ecd23d57e2a7d76233c41888340740.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I recently tackled an interesting challenge that I think could benefit others in the community. The problem? Creating a symmetrical ManyToMany filter widget in the Django admin dashboard. You know, the kind where you can filter and select related objects from both sides of the relationship with the same neat horizontal filter interface.</p>
<h2 id="heading-the-problem">The Problem</h2>
<p>Let's say you have a <code>CompanyStructure</code> model with a ManyToMany relationship to Django's <code>CustomUser</code>. By default, Django admin gives you a nice horizontal filter widget on the <code>CompanyStructure</code> side, but not on the <code>CustomUser</code> side. This creates an inconsistent user experience when managing these relationships.</p>
<h2 id="heading-the-solution">The Solution</h2>
<p>After some digging into Django's internals, I found an elegant solution using Django's <code>RelatedFieldWidgetWrapper</code> and a custom ModelForm. Here's how to implement it:</p>
<h3 id="heading-1-first-lets-look-at-our-models">1. First, let's look at our models:</h3>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> django.contrib.auth.models <span class="hljs-keyword">import</span> AbstractUser
<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models
<span class="hljs-keyword">import</span> treenode.models <span class="hljs-keyword">as</span> treenode_models

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomUser</span>(<span class="hljs-params">AbstractUser</span>):</span>
    objects = CustomUserManager()

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__str__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.username

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CompanyStructure</span>(<span class="hljs-params">treenode_models.TreeNodeModel</span>):</span>
    name = models.CharField(max_length=<span class="hljs-number">255</span>)
    users = models.ManyToManyField(
        CustomUser, 
        related_name=<span class="hljs-string">'company_structures'</span>, 
        blank=<span class="hljs-literal">True</span>
    )
    created_at = models.DateTimeField(auto_now_add=<span class="hljs-literal">True</span>)
    updated_at = models.DateTimeField(auto_now=<span class="hljs-literal">True</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__str__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.name
</code></pre>
<h3 id="heading-2-the-magic-custom-form-with-relatedfieldwidgetwrapper">2. The Magic: Custom Form with RelatedFieldWidgetWrapper</h3>
<p>Here's where the magic happens. We'll create a custom form that adds the horizontal filter widget:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> django <span class="hljs-keyword">import</span> forms
<span class="hljs-keyword">from</span> django.contrib <span class="hljs-keyword">import</span> admin
<span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models
<span class="hljs-keyword">from</span> django.contrib.admin <span class="hljs-keyword">import</span> widgets

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomUserForm</span>(<span class="hljs-params">forms.ModelForm</span>):</span>
    company_structures = forms.ModelMultipleChoiceField(
        queryset=CompanyStructure.objects.all(),
        widget=widgets.RelatedFieldWidgetWrapper(
            widget=widgets.FilteredSelectMultiple(<span class="hljs-string">'company structures'</span>, <span class="hljs-literal">False</span>),
            rel=models.ManyToManyRel(
                field=CustomUser,
                to=CompanyStructure,
                through=CustomUser.company_structures.through
            ),
            admin_site=admin.site
        )
    )

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Meta</span>:</span>
        model = CustomUser
        fields = <span class="hljs-string">'__all__'</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, *args, **kwargs</span>):</span>
        super().__init__(*args, **kwargs)
        <span class="hljs-comment"># Initialize with existing relations</span>
        <span class="hljs-keyword">if</span> self.instance <span class="hljs-keyword">and</span> self.instance.pk:
            self.fields[<span class="hljs-string">'company_structures'</span>].initial = (
                self.instance.company_structures.all()
            )

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">save</span>(<span class="hljs-params">self, commit=True</span>):</span>
        instance = super().save(commit=<span class="hljs-literal">False</span>)
        <span class="hljs-keyword">if</span> commit:
            instance.save()
        <span class="hljs-comment"># Save the ManyToMany relations</span>
        instance.company_structures.set(self.cleaned_data[<span class="hljs-string">'company_structures'</span>])
        <span class="hljs-keyword">return</span> instance
</code></pre>
<h3 id="heading-3-register-with-admin">3. Register with Admin</h3>
<p>Finally, we hook it all up in the admin:</p>
<pre><code class="lang-python"><span class="hljs-meta">@admin.register(CustomUser)</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomUserAdmin</span>(<span class="hljs-params">UserAdmin</span>):</span>
    form = CustomUserForm
    <span class="hljs-comment"># ... other admin configurations ...</span>
</code></pre>
<h2 id="heading-see-how-it-looks">See how it looks</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729728268101/72ce06e6-7526-443a-a6b0-f6c9c2a10513.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-how-it-works">How It Works</h2>
<p>Let's break down the key components that make this solution work:</p>
<ol>
<li><p><strong>RelatedFieldWidgetWrapper</strong>: This is the secret sauce. It's the same widget Django uses internally for related fields, but we're explicitly implementing it for our reverse relationship.</p>
</li>
<li><p><strong>FilteredSelectMultiple</strong>: This creates the actual horizontal filter interface with search functionality.</p>
</li>
<li><p><strong>ManyToManyRel</strong>: This tells Django about the relationship type and provides necessary metadata for the widget to function properly.</p>
</li>
</ol>
<h2 id="heading-key-benefits">Key Benefits</h2>
<ul>
<li><p><strong>Consistent UI</strong>: Users get the same filtering experience from both sides of the relationship</p>
</li>
<li><p><strong>Better UX</strong>: The horizontal filter widget is more user-friendly than a basic select field</p>
</li>
<li><p><strong>Search Functionality</strong>: Built-in search makes it easier to find specific items in large datasets</p>
</li>
</ul>
<h2 id="heading-potential-gotchas">Potential Gotchas</h2>
<ol>
<li><p><strong>Performance</strong>: With large datasets, you might want to optimize the queryset in the ModelMultipleChoiceField</p>
</li>
<li><p><strong>Form Initialization</strong>: Make sure to handle the initial values correctly in the <code>__init__</code> method</p>
</li>
<li><p><strong>Saving</strong>: Don't forget to implement the <code>save</code> method to handle the M2M relationship properly</p>
</li>
</ol>
<h2 id="heading-attention-django-51">Attention: Django 5.1+</h2>
<p>Since we override the form class, we might want to bring back this beauty</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729800172971/6006b665-b65b-4ab8-bb7a-426f37245c15.png" alt class="image--center mx-auto" /></p>
<p>Complete Code: <a target="_blank" href="https://gist.github.com/Kenan7/0a5169242f13b95acd362e5d7a841607">https://gist.github.com/Kenan7/0a5169242f13b95acd362e5d7a841607</a></p>
<h2 id="heading-in-conclusion">In Conclusion</h2>
<p>This solution provides a clean, symmetrical interface for managing ManyToMany relationships in Django admin. While it requires a bit more code than the default setup, the improved user experience makes it worth the effort.</p>
<p>Remember to adapt the code to your specific needs and consider adding any necessary validation or customization to match your project's requirements.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Django Middleware: A Practical Guide]]></title><description><![CDATA[Django middleware is a powerful tool that allows you to process requests and responses globally across your entire Django application. In this post, we'll explore what middleware is, how it works, and walk through some practical examples.
What is Dja...]]></description><link>https://kenan7.com/understanding-django-middleware-a-practical-guide</link><guid isPermaLink="true">https://kenan7.com/understanding-django-middleware-a-practical-guide</guid><category><![CDATA[Django]]></category><category><![CDATA[Middleware]]></category><category><![CDATA[django rest framework]]></category><category><![CDATA[django orm]]></category><dc:creator><![CDATA[Mirkenan Kazımzade]]></dc:creator><pubDate>Fri, 05 Jul 2024 22:23:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/T9rKvI3N0NM/upload/4cdfde2e86f54776b42d5e60fb3e9eb5.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Django middleware is a powerful tool that allows you to process requests and responses globally across your entire Django application. In this post, we'll explore what middleware is, how it works, and walk through some practical examples.</p>
<h2 id="heading-what-is-django-middleware">What is Django Middleware?</h2>
<p>Middleware in Django is a framework of hooks into Django's request/response processing. It's a lightweight, low-level plugin system for globally altering Django's input or output.</p>
<p>Each middleware component is responsible for doing some specific function. For example, Django includes a middleware that adds the CSRF token to responses and another that handles user sessions.</p>
<h2 id="heading-how-does-middleware-work">How Does Middleware Work?</h2>
<p>Middleware classes are called in the order they're defined in the <code>MIDDLEWARE</code> setting. During the request phase, Django calls the <code>process_request()</code> method of each middleware in order. During the response phase, the <code>process_response()</code> methods are called in reverse order.</p>
<p>Here's a simplified view of the request/response cycle:</p>
<ol>
<li><p>Request comes in</p>
</li>
<li><p>Middleware 1 processes request</p>
</li>
<li><p>Middleware 2 processes request</p>
</li>
<li><p>View processes request and produces response</p>
</li>
<li><p>Middleware 2 processes response</p>
</li>
<li><p>Middleware 1 processes response</p>
</li>
<li><p>Response goes out</p>
</li>
</ol>
<h2 id="heading-creating-custom-middleware">Creating Custom Middleware</h2>
<p>Let's look at some examples of custom middleware:</p>
<h3 id="heading-example-1-timing-middleware">Example 1: Timing Middleware</h3>
<p>This middleware will measure how long each request takes to process:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> time

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TimingMiddleware</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, get_response</span>):</span>
        self.get_response = get_response

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__call__</span>(<span class="hljs-params">self, request</span>):</span>
        start_time = time.time()

        response = self.get_response(request)

        duration = time.time() - start_time
        response[<span class="hljs-string">'X-Page-Generation-Duration-ms'</span>] = int(duration * <span class="hljs-number">1000</span>)
        <span class="hljs-keyword">return</span> response
</code></pre>
<p>This middleware adds an <code>X-Page-Generation-Duration-ms</code> header to each response, showing how many milliseconds the request took to process.</p>
<h3 id="heading-example-2-ip-restriction-middleware">Example 2: IP Restriction Middleware</h3>
<p>This middleware will restrict access to certain views based on IP address:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> django.http <span class="hljs-keyword">import</span> HttpResponseForbidden

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IPRestrictionMiddleware</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, get_response</span>):</span>
        self.get_response = get_response

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__call__</span>(<span class="hljs-params">self, request</span>):</span>
        allowed_ips = [<span class="hljs-string">'192.168.1.1'</span>, <span class="hljs-string">'192.168.1.2'</span>]
        ip = request.META.get(<span class="hljs-string">'REMOTE_ADDR'</span>)

        <span class="hljs-keyword">if</span> request.path.startswith(<span class="hljs-string">'/admin/'</span>) <span class="hljs-keyword">and</span> ip <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> allowed_ips:
            <span class="hljs-keyword">return</span> HttpResponseForbidden(<span class="hljs-string">"You are not allowed to access this resource."</span>)

        <span class="hljs-keyword">return</span> self.get_response(request)
</code></pre>
<p>This middleware checks if the request is for the admin area and if so, verifies that the client's IP is in the allowed list.</p>
<h3 id="heading-example-3-request-logging-middleware">Example 3: Request Logging Middleware</h3>
<p>This middleware will log details about each request:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> logging

logger = logging.getLogger(__name__)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RequestLoggingMiddleware</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, get_response</span>):</span>
        self.get_response = get_response

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__call__</span>(<span class="hljs-params">self, request</span>):</span>
        logger.info(<span class="hljs-string">f"Request: <span class="hljs-subst">{request.method}</span> <span class="hljs-subst">{request.path}</span> from <span class="hljs-subst">{request.META.get(<span class="hljs-string">'REMOTE_ADDR'</span>)}</span>"</span>)

        response = self.get_response(request)

        logger.info(<span class="hljs-string">f"Response: <span class="hljs-subst">{response.status_code}</span>"</span>)
        <span class="hljs-keyword">return</span> response
</code></pre>
<p>This middleware logs the HTTP method, path, and IP address for each request, as well as the status code of each response.</p>
<h2 id="heading-using-your-middleware">Using Your Middleware</h2>
<p>To use your custom middleware, add it to the <code>MIDDLEWARE</code> setting in your Django settings file:</p>
<pre><code class="lang-python">MIDDLEWARE = [
    <span class="hljs-comment"># ... other middleware classes ...</span>
    <span class="hljs-string">'path.to.TimingMiddleware'</span>,
    <span class="hljs-string">'path.to.IPRestrictionMiddleware'</span>,
    <span class="hljs-string">'path.to.RequestLoggingMiddleware'</span>,
]
</code></pre>
<p>Remember, the order matters! Middleware classes are processed in the order they appear in this list.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Middleware is a powerful feature in Django that allows you to process requests and responses globally. Whether you're adding security features, logging information, or modifying responses, middleware provides a clean and reusable way to add functionality to your Django application.</p>
<p>By creating custom middleware, you can keep your views clean and focused on their primary logic, while handling cross-cutting concerns at the application level.</p>
]]></content:encoded></item><item><title><![CDATA[How to set up and use proxy in your server | Docker | Docker-compose | Proxy.py]]></title><description><![CDATA[I wanted to run a proxy in my server, I tried everything but still failed to set it up. I tried mitmproxy, squid, and some other proxies that I forgot, yet I somehow failed in all of them. 
After researching a little more I finally found a solution t...]]></description><link>https://kenan7.com/how-to-set-up-and-use-proxy-in-your-server-or-docker-or-docker-compose-or-proxypy</link><guid isPermaLink="true">https://kenan7.com/how-to-set-up-and-use-proxy-in-your-server-or-docker-or-docker-compose-or-proxypy</guid><category><![CDATA[proxy]]></category><category><![CDATA[server]]></category><category><![CDATA[Docker]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Python]]></category><dc:creator><![CDATA[Mirkenan Kazımzade]]></dc:creator><pubDate>Fri, 04 Dec 2020 18:52:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1607107782478/RxTjtMHKE.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I wanted to run a proxy in my server, I tried everything but still failed to set it up. I tried mitmproxy, squid, and some other proxies that I forgot, yet I somehow failed in all of them. </p>
<p>After researching a little more I finally found a solution that works perfectly. <a target="_blank" href="https://github.com/abhinavsingh/proxy.py">Proxy.py</a></p>
<p>This awesome tool is written in python, has docker configurations, and HTTPS certificate generator.</p>
<p>So let's start.</p>
<p>I reckon that you are already on your server's terminal, you have <code>git</code> and <code>python3-virtualenv</code> installed.</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/abhinavsingh/proxy.py.git
</code></pre>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> proxy.py
</code></pre>
<pre><code class="lang-bash">python3 -m venv env
. env/bin/activate
</code></pre>
<pre><code class="lang-bash">pip install -r requirements.txt
</code></pre>
<p>So if you run all commands so far, you should be good.</p>
<p>Now, this is where we do a little customization. In proxy.py docs, they are building and running containers through docker engine, but we will create our own docker-compose file for more <em>comfort</em>.</p>
<p>if you don't have already installed docker and docker-compose please follow these links:</p>
<p>for docker: <a target="_blank" href="https://docs.docker.com/get-docker/">docker/download</a></p>
<p>for docker-compose (ubuntu): <a target="_blank" href="https://linuxize.com/post/how-to-install-and-use-docker-compose-on-ubuntu-20-04/#installing-docker-compose-on-ubuntu">linuxize/docker-compose</a> </p>
<p>Let's dig in.</p>
<p>create a file called <code>docker-compose.yml</code> in our cloned directory (proxy.py)</p>
<pre><code class="lang-bash">nano docker-compose.yml
</code></pre>
<p>paste this context</p>
<pre><code class="lang-yml"><span class="hljs-attr">version:</span> <span class="hljs-string">"3"</span>

<span class="hljs-attr">services:</span>
  <span class="hljs-attr">proxy:</span>
    <span class="hljs-attr">build:</span> <span class="hljs-string">.</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">custom-proxy</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"8899:8899"</span>
    <span class="hljs-attr">restart:</span> <span class="hljs-string">always</span>
</code></pre>
<p>if you have an entry for <code>hosts</code> file you can use <code>extra-hosts</code></p>
<p>here is sample</p>
<pre><code class="lang-yml"><span class="hljs-attr">services:</span>
  <span class="hljs-attr">proxy:</span>
    <span class="hljs-attr">build:</span> <span class="hljs-string">.</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">custom-proxy</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"8899:8899"</span>
    <span class="hljs-attr">restart:</span> <span class="hljs-string">always</span>
    <span class="hljs-attr">extra_hosts:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"example.com:1.2.3.4"</span>
</code></pre>
<p>Let me break these lines for you</p>
<p><strong>proxy</strong> is just the name of the service</p>
<p><strong>build</strong> is where our Dockerfile is located (yes it's in the current directory!)</p>
<p><strong>container_name</strong> is not necessary, I just did it because I like it that way</p>
<p><strong>ports</strong>: we expose the ports to the public (proxy.py default is 8899)</p>
<p><strong>restart: always</strong> is simply saying start running container again if an error occurs</p>
<p>That's that.</p>
<p>Now that we have our docker-compose file we can update and run our containers more easily! Run the following command to build and get your container up.</p>
<pre><code class="lang-bash">sudo docker-compose build
</code></pre>
<p>when this command finishes you'll have something like this</p>
<pre><code class="lang-docker">...
Step 14/15 : ENTRYPOINT [ "proxy" ]
 ---&gt; Using cache
 ---&gt; a18dd7a78abb
Step 15/15 : CMD [ "--hostname=0.0.0.0" ]
 ---&gt; Using cache
 ---&gt; 012db77b2da2
Successfully built 012db77b2da2
Successfully tagged proxypy_proxy:latest
</code></pre>
<p>to get you container up and running</p>
<pre><code class="lang-bash">sudo docker-compose up
</code></pre>
<p><span>note: add -d parameter at the end to run in the background</span></p>
<pre><code class="lang-bash">Creating exbir-proxy ... <span class="hljs-keyword">done</span>
Attaching to exbir-proxy
exbir-proxy | 2020-12-04 18:43:35,267 - pid:1 [I] load_plugins:334 - Loaded plugin proxy.http.proxy.HttpProxyPlugin
exbir-proxy | 2020-12-04 18:43:35,268 - pid:1 [I] listen:113 - Listening on 0.0.0.0:8899
exbir-proxy | 2020-12-04 18:43:35,277 - pid:1 [I] start_workers:136 - Started 2 workers
</code></pre>
<p>CONGRATULATIONS! your proxy works in your server on port 8899!</p>
<p>At this point, I have a little bonus for you. If you have your own customizations too, to make docker-compose controls easier, go ahead and make <em>temporary</em> alias for yourself. </p>
<pre><code class="lang-bash"><span class="hljs-built_in">alias</span> dd=<span class="hljs-string">"sudo docker-compose down -v &amp;&amp; sudo docker-compose build &amp;&amp; sudo docker-compose up -d"</span>
</code></pre>
<p>You can add it to your .bashrc (or other shells) file if you want to make it permanent.</p>
<p>Please ask me any questions related to this post!</p>
]]></content:encoded></item></channel></rss>