<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ PaaS - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ PaaS - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 18 Jun 2026 23:23:38 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/paas/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ The Tradeoff That Slows Production Teams Down: Flexibility vs Actually Shipping ]]>
                </title>
                <description>
                    <![CDATA[ Every company says it wants speed. Roadmaps talk about velocity. Leadership meetings talk about reducing cycle time. Quarterly goals talk about faster execution and quicker releases. Every business wa ]]>
                </description>
                <link>https://www.freecodecamp.org/news/the-tradeoff-that-slows-production-teams-down-flexibility-vs-actually-shipping/</link>
                <guid isPermaLink="false">6a19ccc19e433f18f384364b</guid>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ production ]]>
                    </category>
                
                    <category>
                        <![CDATA[ deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ PaaS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Fri, 29 May 2026 17:28:33 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/495a017a-0f6f-4e3b-8d55-6c3854917c51.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Every company says it wants speed.</p>
<p>Roadmaps talk about velocity. Leadership meetings talk about reducing cycle time. Quarterly goals talk about faster execution and quicker releases.</p>
<p>Every business wants teams moving faster.</p>
<p>Then many of those same companies make a decision that quietly slows everything down. They optimise for infrastructure flexibility instead of product delivery.</p>
<p>It sounds reasonable in the beginning. Teams want control. Engineers want options. Platform architects want systems that can support every future scenario.</p>
<p>So production teams start building infrastructure ecosystems around themselves.</p>
<p>Deployment pipelines get built from scratch. Cloud resources become heavily customised. Internal platforms gain endless knobs, switches, and configuration layers. New projects begin with architecture discussions instead of customer problems.</p>
<p>Months later, software delivery slows down.</p>
<p>Product teams miss timelines. Releases move out by quarters. Customer feedback arrives later. Competitors keep shipping.</p>
<p>The tradeoff hiding underneath all of this is simple. Teams choose flexibility over actually shipping.</p>
<p>And beyond a certain point, flexibility becomes one of the most expensive forms of organisational drag a company can create.</p>
<h3 id="heading-what-well-cover">What We'll Cover:</h3>
<ul>
<li><p><a href="#heading-the-myth-that-more-flexibility-creates-better-production-systems">The Myth That More Flexibility Creates Better Production Systems</a></p>
</li>
<li><p><a href="#heading-infrastructure-ownership-quietly-becomes-a-second-business">Infrastructure Ownership Quietly Becomes a Second Business</a></p>
</li>
<li><p><a href="#heading-the-real-cost-is-delayed-customer-learning">The Real Cost Is Delayed Customer Learning</a></p>
</li>
<li><p><a href="#heading-paas-changes-the-optimisation-function">PaaS Changes the Optimisation Function</a></p>
</li>
<li><p><a href="#heading-the-best-production-teams-remove-decisions">The Best Production Teams Remove Decisions</a></p>
</li>
<li><p><a href="#heading-custom-infrastructure-usually-solves-problems-nobody-has-yet">Custom Infrastructure Usually Solves Problems Nobody Has Yet</a></p>
</li>
<li><p><a href="#heading-the-real-competitive-advantage-is-shipping-faster">The Real Competitive Advantage Is Shipping Faster</a></p>
</li>
<li><p><a href="#heading-when-paas-might-not-be-the-right-choice">When PaaS Might Not Be the Right Choice</a></p>
</li>
<li><p><a href="#heading-stop-building-infrastructure-businesses-by-accident">Stop Building Infrastructure Businesses By Accident</a></p>
</li>
</ul>
<h2 id="heading-the-myth-that-more-flexibility-creates-better-production-systems">The Myth That More Flexibility Creates Better Production Systems</h2>
<p>Engineering teams love optionality. The logic sounds convincing.</p>
<p>If infrastructure is fully customizable, teams can adapt to future requirements. If deployment systems are built internally, every use case can be supported. If every layer is configurable, engineers can optimise for unique situations.</p>
<p>This feels like responsible engineering. But it often becomes expensive business behaviour.</p>
<p>Most production teams massively overestimate how often they need deep infrastructure flexibility.</p>
<p>What actually happens becomes predictable.</p>
<p>A product team starts a new initiative. Instead of shipping an early version and learning from customers, discussions begin.</p>
<ul>
<li><p>Should Kubernetes clusters be organised by team or service?</p>
</li>
<li><p>Should CI/CD use GitHub Actions or Jenkins?</p>
</li>
<li><p>Should secrets management use Vault or cloud-native tooling?</p>
</li>
<li><p>Should observability use Prometheus or Datadog?</p>
</li>
<li><p>Should deployment strategies use canary releases, <a href="https://www.redhat.com/en/topics/devops/what-is-blue-green-deployment">blue-green deployments</a>, or something custom?</p>
</li>
</ul>
<p>Weeks disappear. No customer sees anything. No assumptions get tested. No learning happens.</p>
<p>Meanwhile, product managers wait. Leadership waits. Customers wait.</p>
<p>Even with <a href="https://sevalla.com/blog/building-apps-with-sevalla-and-claude-code/">agentic coding tools</a> like Claude generating code, scaffolding systems and accelerating implementation, teams still lose speed when every output collides with infrastructure decisions and deployment debates.</p>
<p>The problem isn't technology. The problem is optimising around theoretical future flexibility instead of present business outcomes.</p>
<p>Software creates value when customers use it. Everything else is support work.</p>
<h2 id="heading-infrastructure-ownership-quietly-becomes-a-second-business">Infrastructure Ownership Quietly Becomes a Second Business</h2>
<p>Traditional deployment models accidentally create a dangerous pattern: companies think they are building products. Slowly, they start building infrastructure organisations.</p>
<p>Production teams provision servers. Then networking. Then IAM systems. Then deployment pipelines. Then, observability layers. Then secrets management. Then autoscaling. Then rollback systems.</p>
<p>Every decision feels reasonable in isolation. But collectively, teams create an operational machine they now own forever.</p>
<p>And ownership is where the hidden cost appears.</p>
<p>Because infrastructure work doesn't end after launch. It expands. Pipelines need maintenance. Security policies change. Monitoring systems require tuning. Platform dependencies break. Internal tooling needs upgrades.</p>
<p>Production teams gradually spend more time maintaining systems around software than improving software itself.</p>
<p>This creates a strange situation: highly paid engineers become caretakers for infrastructure instead of builders of customer value.</p>
<p>No customer purchases a product because deployment pipelines have become elegant. No customer upgrades because IAM policies are beautifully designed. No competitor loses market share because Kubernetes YAML looks sophisticated.</p>
<p>Customers care about products solving problems. Infrastructure only matters when it slows product delivery.</p>
<p>And infrastructure ownership creates endless opportunities for that to happen.</p>
<h2 id="heading-the-real-cost-is-delayed-customer-learning">The Real Cost Is Delayed Customer Learning</h2>
<p>The biggest cost of infrastructure complexity isn't engineering effort. It's delayed learning.</p>
<p>Software companies win through feedback loops. Teams ship something. Customers react. Teams learn. Products improve.</p>
<p>The faster this cycle operates, the stronger the company becomes.</p>
<p>Infrastructure work interrupts that loop. Every month spent building deployment systems is a month where customers aren't using new features. Every quarter spent designing internal platforms delays customer feedback. Every architecture discussion delays real market signals.</p>
<p>This is where many organisations misunderstand velocity.</p>
<p>They look at sprint metrics. They measure tickets completed. They count engineering output.</p>
<p>But business speed isn't measured through internal activity. Business speed measures how quickly ideas become customer reality.</p>
<p>Infrastructure ownership slows that process dramatically. And slower learning creates slower companies.</p>
<h2 id="heading-paas-changes-the-optimisation-function">PaaS Changes the Optimisation Function</h2>
<p>This is where <a href="https://www.freecodecamp.org/news/from-metrics-to-meaning-how-paas-helps-developers-understand-production/">Platform as a Service</a> changes the equation.</p>
<p>PaaS forces organisations to optimise around shipping rather than infrastructure ownership. That shift matters more than most teams realise.</p>
<p>Instead of spending weeks designing deployment architecture, production teams connect repositories and deploy.</p>
<p>Instead of building pipelines manually, pipelines already exist.</p>
<p>Instead of designing scaling systems, scaling becomes infrastructure behaviour rather than engineering work.</p>
<p>Instead of repeatedly building foundations, infrastructure becomes a utility.</p>
<p>That sounds simple. It should be simple. Deployment should feel boring. But the fact that deployment often becomes a major organisational project is usually evidence of unnecessary complexity rather than unavoidable complexity.</p>
<p>PaaS providers remove entire categories of decisions. And while many engineers see that as a compromise, it's often the opposite.</p>
<p>Constraints create speed. Speed creates learning. Learning creates better products.</p>
<h2 id="heading-the-best-production-teams-remove-decisions">The Best Production Teams Remove Decisions</h2>
<p>There's a common misconception that elite engineering organisations maximise options. The opposite is often true.</p>
<p>High-performing production teams aggressively eliminate decisions. They standardise. They create defaults. They remove unnecessary choices.</p>
<p>Because every decision carries a cost.</p>
<p>Cognitive load grows. Coordination increases. Meetings multiply. Dependencies expand. Eventually, the workaround software becomes larger than the software itself.</p>
<p>PaaS systems follow a different philosophy. They intentionally reduce optionality.</p>
<p>That reduction creates focus. And focus creates product velocity. Product velocity creates business outcomes.</p>
<p>The chain is straightforward. Too many organisations break it by introducing infrastructure ownership far too early.</p>
<h2 id="heading-custom-infrastructure-usually-solves-problems-nobody-has-yet">Custom Infrastructure Usually Solves Problems Nobody Has Yet</h2>
<p>One of the most expensive habits in software companies is solving future problems before current ones exist.</p>
<p>Teams build for scale before scale exists. They create multi-region architectures before international users arrive. They build deployment frameworks before deployment pain appears.</p>
<p>This usually comes from good intentions. Engineers want to avoid future rewrites. But the irony is that premature flexibility creates an immediate business slowdown.</p>
<p>A startup with twenty engineers shouldn't operate like a company with ten thousand engineers. Yet many production teams copy infrastructure patterns from giant technology firms.</p>
<p>What gets ignored is context. Large technology companies have entire platform teams maintaining internal systems. They have thousands of engineers supporting infrastructure investments.</p>
<p>Most companies do not.</p>
<p>Copying technical architecture without copying organisational scale creates enormous inefficiency.</p>
<p>PaaS acts as protection against this behaviour. It prevents teams from accidentally becoming infrastructure companies before they become successful product companies.</p>
<h2 id="heading-the-real-competitive-advantage-is-shipping-faster">The Real Competitive Advantage Is Shipping Faster</h2>
<p>Companies rarely lose because infrastructure flexibility was insufficient. They lost because competitors learned faster.</p>
<p>Speed matters. Not speed in sprint or <a href="https://linear.app/">linear dashboards</a>. Not speed in story points.</p>
<p>Actual speed. The ability to move ideas into production quickly. The ability to test assumptions rapidly. The ability to learn continuously.</p>
<p>Shipping creates learning. Learning creates improvement. Improvement creates advantage.</p>
<p>Infrastructure complexity interrupts this loop. PaaS strengthens it.</p>
<p>This is why deployment decisions should never be treated as purely technical discussions. They are business decisions.</p>
<p>Infrastructure ownership affects company velocity. Velocity affects market outcomes.</p>
<p>The argument isn't about servers. The argument is about competitive speed.</p>
<h2 id="heading-when-paas-might-not-be-the-right-choice">When PaaS Might Not Be the Right Choice</h2>
<p>There are situations where PaaS can become limiting.</p>
<p>Organisations with highly specialised infrastructure requirements may require direct control over networking, security layers, hardware optimisation, or deployment behaviour.</p>
<p>Some industries have regulatory requirements that create unusually specific infrastructure needs.</p>
<p>Large organisations with mature platform engineering teams may also justify custom infrastructure investments.</p>
<p>There are also cases where platform costs become meaningful at very large scale.</p>
<p>These scenarios exist. But many companies use edge cases as justification years before they become relevant. They prepare for infrastructure problems they may never have while struggling to ship ordinary product releases today.</p>
<p>That sequence creates unnecessary friction.</p>
<h2 id="heading-stop-building-infrastructure-businesses-by-accident">Stop Building Infrastructure Businesses By Accident</h2>
<p>Engineering culture often celebrates flexibility.</p>
<p>Flexibility sounds sophisticated. It sounds future-proof. It sounds like good systems thinking.</p>
<p>But flexibility carries a cost. Every additional option creates complexity. Every additional decision slows movement. Every additional layer creates maintenance work.</p>
<p>Production teams should ask a simpler question. Does this help us ship customer-facing software faster? If the answer is no, it deserves scrutiny.</p>
<p>Too many companies accidentally build infrastructure ecosystems that optimise for hypothetical future needs.</p>
<p>Meanwhile, competitors deploy products, learn from customers and improve faster.</p>
<p>Shipping beats flexibility. And for many production teams, choosing a PaaS is one of the clearest ways to prove it.</p>
<p>Hope you enjoyed this article. You can <a href="https://linkedin.com/in/manishmshiva">connect with me on LinkedIn</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Avoid Rebuilding Infrastructure for Every New Project ]]>
                </title>
                <description>
                    <![CDATA[ Every production engineering team knows the pattern. A new project begins with energy. Product goals are clear. Deadlines are ambitious. Teams want to move quickly and deliver something customers can  ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-avoid-rebuilding-infrastructure-for-every-new-project/</link>
                <guid isPermaLink="false">6a0f78aad8e265f60d5f7b56</guid>
                
                    <category>
                        <![CDATA[ PaaS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Kubernetes ]]>
                    </category>
                
                    <category>
                        <![CDATA[ distributed system ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Thu, 21 May 2026 21:27:06 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5fc16e412cae9c5b190b6cdd/6c414744-42af-430a-8bbd-76a33b564e4b.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Every production engineering team knows the pattern. A new project begins with energy. Product goals are clear. Deadlines are ambitious. Teams want to move quickly and deliver something customers can use.</p>
<p>Then the real work starts. Infrastructure must be provisioned. CI/CD pipelines need to be set up. Secrets require management. Monitoring needs wiring. Databases need deployment. Logging needs configuration. Security policies need implementation. Networking rules need review.</p>
<p>Weeks disappear before users see anything useful. Many organizations treat this as normal. They call it engineering rigour. They assume this operational setup phase is simply part of software development.</p>
<p>It is not.</p>
<p>For teams already running production systems, rebuilding infrastructure foundations for every new project is organizational waste. It is repetitive operational labour disguised as an engineering discipline.</p>
<p>The uncomfortable question is not, “How can we do this setup faster?” The real question is: why are we still doing it ourselves at all?</p>
<p>This is where <a href="https://www.freecodecamp.org/news/from-metrics-to-meaning-how-paas-helps-developers-understand-production/">Platform as a Service</a> changes the conversation. A good PaaS shifts the starting point from “rebuild the foundations” to “start shipping. Because new projects should begin closer to customer value, not closer to infrastructure assembly.</p>
<p>In this article, we'll look at why many production teams waste time rebuilding the same infrastructure for every new project, how PaaS helps remove that work, and why engineering teams should question if managing complex infrastructure still makes sense for most projects.</p>
<h2 id="heading-what-well-cover">What We'll Cover:</h2>
<ul>
<li><p><a href="#heading-most-teams-were-not-hired-to-build-infrastructure">Most Teams Were Not Hired to Build Infrastructure</a></p>
</li>
<li><p><a href="#heading-aws-primitives-are-not-a-competitive-advantage">AWS Primitives Are Not a Competitive Advantage</a></p>
</li>
<li><p><a href="#heading-most-teams-should-not-be-managing-kubernetes">Most Teams Should Not Be Managing Kubernetes</a></p>
</li>
<li><p><a href="#heading-paas-changes-the-starting-point">PaaS Changes the Starting Point</a></p>
</li>
<li><p><a href="#heading-repetition-creates-hidden-organizational-waste">Repetition Creates Hidden Organizational Waste</a></p>
</li>
<li><p><a href="#heading-standardization-is-usually-faster-than-flexibility">Standardization Is Usually Faster Than Flexibility</a></p>
</li>
<li><p><a href="#heading-platform-teams-become-multipliers">Platform Teams Become Multipliers</a></p>
</li>
<li><p><a href="#heading-easier-starts-create-more-innovation">Easier Starts Create More Innovation</a></p>
</li>
<li><p><a href="#heading-when-specialized-control-actually-matters">When Specialized Control Actually Matters</a></p>
</li>
<li><p><a href="#heading-starting-from-zero-is-a-process-failure">Starting From Zero Is a Process Failure</a></p>
</li>
</ul>
<h2 id="heading-most-teams-were-not-hired-to-build-infrastructure"><strong>Most Teams Were Not Hired to Build Infrastructure</strong></h2>
<p>Software teams exist to solve business problems. Customers do not care whether Kubernetes manifests were structured elegantly. They do not admire carefully designed Terraform modules. They do not celebrate handcrafted networking policies.</p>
<p>Customers care about outcomes. They care about faster onboarding. Better recommendations. Smoother payments. Fewer bugs. Simpler workflows.</p>
<p>Yet many engineering organizations spend huge portions of time doing work customers never see.</p>
<p>Teams repeatedly create deployment pipelines. Configure environments. Manage certificates. Set up observability stacks. Tune infrastructure rules. Assemble cloud primitives.</p>
<p>Infrastructure matters. Reliability matters. Security matters.</p>
<p>The problem is duplication. If every project independently recreates the same operational systems, organizations keep rebuilding internal platforms over and over again without admitting it.</p>
<p>This behaviour has become so normalized that teams barely notice it anymore. But rebuilding the same foundation repeatedly is not operational maturity. It is inefficiency scaled across the organization.</p>
<h2 id="heading-aws-primitives-are-not-a-competitive-advantage"><strong>AWS Primitives Are Not a Competitive Advantage</strong></h2>
<p>Many teams confuse cloud ownership with strategic advantage. Owning Kubernetes clusters does not create differentiation. Managing IAM rules does not create customer value. Writing infrastructure glue code does not strengthen market position.</p>
<p>These are implementation details. Yet many organizations spend extraordinary energy managing them as if they are core business assets.</p>
<p>Some teams effectively become part-time infrastructure companies without realizing it. Their engineers slowly accumulate operational responsibilities until maintaining systems consumes more effort than delivering products.</p>
<p>The outcome becomes predictable. Infrastructure expands. Operational complexity grows. Delivery speed declines. Nobody notices because the pain arrives gradually.</p>
<p>A team starts with one Kubernetes cluster. Then another environment appears. More deployment pipelines emerge. Additional tooling gets layered on top. Logging systems become fragmented. Monitoring evolves differently across products.</p>
<p>Eventually, teams spend increasing amounts of time maintaining systems they never intended to own.</p>
<p>Infrastructure ownership is often not a strategy. It is inertia.</p>
<h2 id="heading-most-teams-should-not-be-managing-kubernetes"><strong>Most Teams Should Not Be Managing Kubernetes</strong></h2>
<p><a href="https://www.freecodecamp.org/news/what-does-k8s-mean-kubernetes-setup-guide/">Kubernetes</a> has become an engineering culture. It appears in architecture diagrams, conference talks, hiring requirements, and internal roadmaps. Its adoption often feels inevitable.</p>
<p>But normalization and necessity are not the same thing. Many organizations adopted Kubernetes because industry momentum made it seem like the default path. Not because they had workloads that required its complexity. But the result is predictable.</p>
<p>Small and medium teams end up managing orchestration systems designed for massive operational environments.</p>
<p>They maintain YAML configurations, networking layers, ingress systems, deployment strategies, and operational tooling stacks before delivering meaningful product value. This has become strangely accepted.</p>
<p>A ten-person engineering team maintaining infrastructure patterns designed for internet-scale organizations should raise serious questions. A small team pretending to be a platform team is an operational dysfunction.</p>
<p>Many companies adopt infrastructure complexity built for organizations operating at a vastly different scale. They inherit the burden without inheriting the benefits.</p>
<h2 id="heading-paas-changes-the-starting-point"><strong>PaaS Changes the Starting Point</strong></h2>
<p><a href="https://www.freecodecamp.org/news/the-hidden-tax-of-infrastructure-why-your-team-shouldn-t-be-running-it-anymore/">Traditional infrastructure</a> approaches force teams to think from the bottom upward. Servers come first. Then operating systems. Then networking. Then deployment systems. Then monitoring. Eventually, applications arrive.</p>
<p>PaaS reverses this sequence. Developers begin with applications and business goals. The platform absorbs operational complexity.</p>
<p>Teams stop asking, “How do we provision resources?” They start asking, “What problem are we solving?” That sounds like a small shift. In practice, it changes everything.</p>
<p>A mature PaaS environment often provides deployment pipelines, integrated observability, databases, scaling behaviour, security controls, and operational standards before a team writes meaningful application logic.</p>
<p>Projects begin with product development rather than infrastructure construction. That dramatically changes time-to-value.</p>
<h2 id="heading-repetition-creates-hidden-organizational-waste"><strong>Repetition Creates Hidden Organizational Waste</strong></h2>
<p>Organizations often underestimate operational waste because repetitive work feels familiar. Setting up a deployment pipeline may consume only a few days. Configuring logging may feel routine. Creating security rules may seem manageable.</p>
<p>No individual task appears expensive. The cost appears when repetition scales.</p>
<p>If ten projects independently spend two weeks rebuilding nearly identical operational systems, months of engineering capacity disappear. Those engineers could have shipped customer capabilities. They could have reduced friction. They could have tested new ideas. Instead, they rebuilt plumbing.</p>
<p>Engineering teams understand leverage in nearly every other area. Nobody rewrites sorting algorithms for every application. Nobody recreates database engines from scratch. Nobody builds networking stacks repeatedly.</p>
<p>Reuse is accepted as basic engineering wisdom. Infrastructure should not receive special treatment. Build once. Reuse many times.</p>
<p>PaaS simply applies software engineering principles to operational systems.</p>
<h2 id="heading-standardization-is-usually-faster-than-flexibility"><strong>Standardization Is Usually Faster Than Flexibility</strong></h2>
<p>Engineering teams often resist standardization because they fear losing control. Every project feels unique. Every system appears different. The desire for flexibility sounds reasonable.</p>
<p>But complete flexibility often creates operational chaos. Different teams deploy applications differently. Logging behaves inconsistently. Monitoring varies across systems. Security implementations drift.</p>
<p>Documentation fragments. Onboarding slows. Incident response becomes harder. Complexity quietly accumulates.</p>
<p>PaaS introduces constraints, and many engineers instinctively resist constraints. They should not. Useful constraints often increase speed.</p>
<p>Predictable deployment patterns reduce confusion. Shared monitoring standards simplify troubleshooting. Consistent environments reduce cognitive overhead.</p>
<p>Developers spend less energy understanding infrastructure differences and more time delivering product functionality.</p>
<p>Consistency compounds.</p>
<h2 id="heading-platform-teams-become-multipliers"><strong>Platform Teams Become Multipliers</strong></h2>
<p>Many organizations interpret PaaS as buying a vendor product. That misses the bigger idea.</p>
<p>PaaS is fundamentally about creating reusable capabilities. Some organizations buy platforms. Others build internal platforms.</p>
<p>The principle remains the same.</p>
<p>A platform team creates systems once and allows everyone else to benefit. Instead of dozens of product teams independently solving operational problems, a dedicated group centralizes expertise and builds reusable solutions.</p>
<p>The effect becomes substantial. One deployment improvement accelerates every future release. One observability improvement strengthens every application. One security enhancement protects every team.</p>
<p>Platform teams create organizational leverage. Without this model, expertise stays fragmented. With it, expertise compounds.</p>
<h2 id="heading-easier-starts-create-more-innovation"><strong>Easier Starts Create More Innovation</strong></h2>
<p>Operational friction changes behaviour. When launching projects becomes expensive, organizations become cautious. Teams avoid experiments. Small ideas feel risky. Prototypes become difficult to justify.</p>
<p>Over time, innovation slows. Not because organizations lack ideas, but because starting became too expensive.</p>
<p>Teams running mature platforms understand this relationship. Reducing startup friction increases experimentation. Smaller projects become practical. Learning cycles become shorter.</p>
<p>New ideas appear more often because the cost of testing them falls dramatically. The easier it becomes to launch something, the more opportunities organizations create.</p>
<p>PaaS reduces startup friction. That reduction changes culture.</p>
<h2 id="heading-when-specialized-control-actually-matters"><strong>When Specialized Control Actually Matters</strong></h2>
<p>There are exceptions. Massive data platforms, highly specialized machine learning systems, and extremely customized environments may require lower-level infrastructure ownership.</p>
<p>Some workloads genuinely need deeper operational control. But these scenarios are exceptions, not defaults. Too many teams inherit infrastructure complexity designed for edge cases and treat it as standard practice.</p>
<p>Most production applications do not need custom orchestration layers. Most teams do not need to own Kubernetes. Most engineering groups do not need to spend weeks assembling infrastructure before shipping software.</p>
<p>The default assumption should be the opposite.</p>
<h2 id="heading-starting-from-zero-is-a-process-failure"><strong>Starting From Zero Is a Process Failure</strong></h2>
<p>Many organizations normalize unnecessary operational drag. Long setup cycles become accepted. Infrastructure duplication becomes routine. Cloud complexity becomes expected.</p>
<p>Eventually, teams stop questioning it. They assume this is simply how engineering works. It is not.</p>
<p>If launching a new application requires weeks of foundational setup before customer value appears, that is not an engineering discipline.</p>
<p>The goal was never to become an infrastructure company. It was to ship software.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Why Your “Simple Deploy” Turned Into a Week of Infrastructure Work ]]>
                </title>
                <description>
                    <![CDATA[ If you're running production workloads, this guide is for you. It's not about side projects, early-stage experiments, or a single-service app with low traffic. This is for teams shipping real systems. ]]>
                </description>
                <link>https://www.freecodecamp.org/news/why-your-simple-deploy-turned-into-a-week-of-infrastructure-work/</link>
                <guid isPermaLink="false">6a022071fca21b0d4b57374f</guid>
                
                    <category>
                        <![CDATA[ deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ PaaS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ infrastructure ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Mon, 11 May 2026 18:31:13 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/14f4724b-fb2b-4454-a3dd-3d250e126f50.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you're running production workloads, this guide is for you.</p>
<p>It's not about side projects, early-stage experiments, or a single-service app with low traffic.</p>
<p>This is for teams shipping real systems. Systems with users, uptime expectations, and release pressure.</p>
<p>Because at that stage, your deploy process is no longer a convenience. It's part of your product.</p>
<p>And right now, for most teams, it's the weakest part.</p>
<p>In this article, we'll look at why deployment complexity keeps growing as systems scale, how modern tooling unintentionally pushes teams into platform engineering work, and why many production teams are rethinking the infrastructure they manage themselves.</p>
<p>We'll also look at where Platform as a Service (PaaS) fits into this shift, what trade-offs it introduces, and when adopting one actually makes sense.</p>
<h3 id="heading-what-well-cover">What We'll Cover:</h3>
<ul>
<li><p><a href="#heading-the-promise-you-were-sold">The Promise You Were Sold</a></p>
</li>
<li><p><a href="#heading-the-hidden-contract-you-are-already-operating-under">The Hidden Contract You Are Already Operating Under</a></p>
</li>
<li><p><a href="#heading-you-are-already-acting-like-a-platform-team">You Are Already Acting Like a Platform Team</a></p>
</li>
<li><p><a href="#heading-the-cost-is-not-complexity-it-is-time">The Cost Is Not Complexity. It Is Time</a></p>
</li>
<li><p><a href="#heading-why-it-works-on-my-machine-still-exists">Why “It Works on My Machine” Still Exists</a></p>
</li>
<li><p><a href="#heading-fragmentation-is-the-root-problem">Fragmentation Is the Root Problem</a></p>
</li>
<li><p><a href="#heading-this-model-breaks-as-you-scale">This Model Breaks as You Scale</a></p>
</li>
<li><p><a href="#heading-the-shift-toward-platforms">The Shift Toward Platforms</a></p>
</li>
<li><p><a href="#heading-what-you-stop-paying-for">What You Stop Paying For</a></p>
</li>
<li><p><a href="#heading-from-infrastructure-work-back-to-product-work">From Infrastructure Work Back to Product Work</a></p>
</li>
<li><p><a href="#heading-collapsing-the-stack">Collapsing the Stack</a></p>
</li>
<li><p><a href="#heading-the-trade-off-you-are-actually-making">The Trade-Off You Are Actually Making</a></p>
</li>
<li><p><a href="#heading-when-this-becomes-urgent">When This Becomes Urgent</a></p>
</li>
<li><p><a href="#heading-what-a-simple-deploy-actually-means">What a “Simple Deploy” Actually Means</a></p>
</li>
<li><p><a href="#heading-closing-thought">Closing Thought</a></p>
</li>
</ul>
<h2 id="heading-the-promise-you-were-sold">The Promise You Were Sold</h2>
<p>Every modern stack makes the same promise: Shipping is easy. Deploying is automated. Infrastructure is abstracted away. Push your code. Watch it go live.</p>
<p>That promise works , until it doesn’t.</p>
<p>And when it breaks, it doesn't fail gracefully. It expands.</p>
<p>A “simple deploy” turns into a multi-day investigation across systems you never intended to own.</p>
<p>Not because your team is careless. Because the model itself assumes you'll take on more responsibility than it admits.</p>
<h2 id="heading-the-hidden-contract-you-are-already-operating-under">The Hidden Contract You Are Already Operating Under</h2>
<p>When you deploy today, you're not just shipping code. You're agreeing to run a <a href="https://www.splunk.com/en_us/blog/learn/distributed-systems.html">distributed system</a> of tools.</p>
<p>You own the build pipeline, the container lifecycle, the runtime configuration, the network rules, the secrets layer, the scaling logic, and the observability stack.</p>
<p>Each of these is presented as a separate concern. In reality, they're tightly coupled.</p>
<p>And you're the only layer holding them together. That's the hidden contract.</p>
<h2 id="heading-you-are-already-acting-like-a-platform-team">You Are Already Acting Like a Platform Team</h2>
<p>If your deploy process involves CI pipelines, container registries, cloud services, environment variables, and monitoring tools, you're not just an application team anymore. You're running a platform.</p>
<p>You're defining how code moves from commit to production. You're deciding how failures are handled. And you're shaping how services communicate.</p>
<p>That's platform engineering work.</p>
<p>The issue isn't that this work exists. The issue is that most teams take it on unintentionally, without the structure, tooling, or dedicated ownership a real platform team would require.</p>
<h2 id="heading-the-cost-is-not-complexity-it-is-time">The Cost Is Not Complexity. It Is Time</h2>
<p>It's easy to describe this problem as “complexity.” But that undersells it.</p>
<p>The real cost shows up in how your team spends its time.</p>
<p>Deploys that should take minutes stretch into hours. Then days. Engineers context-switch from product work into debugging <a href="https://www.youtube.com/watch?v=dhiGWtnk4Rk">CI caches</a>, fixing misconfigured secrets, or tracing network failures across services.</p>
<p>Releases slow down. Not because your team can't build features, but because shipping them becomes unpredictable.</p>
<p>Onboarding gets harder. New engineers don't just learn the codebase. They have to learn your deployment system.</p>
<p>None of this appears on a roadmap. But it directly impacts how fast you can move.</p>
<h2 id="heading-why-it-works-on-my-machine-still-exists">Why “It Works on My Machine” Still Exists</h2>
<p>We were supposed to have solved this: Containers. Infrastructure as code. Reproducible builds.</p>
<p>Yet the gap between local and production still shows up at the worst possible moment.</p>
<p>Because the problem was never just environment parity. It's system parity.</p>
<p>Your local setup doesn't include the same limits, permissions, network paths, or scaling behavior as production.</p>
<p>Those differences only surface when everything is wired together. Which means they surface during deploys.</p>
<h2 id="heading-fragmentation-is-the-root-problem">Fragmentation Is the Root Problem</h2>
<p>Modern tooling didn't remove infrastructure complexity. It redistributed it.</p>
<p>Instead of managing servers, you manage integrations between services. Instead of a single failure domain, you have many.</p>
<p>A deploy can fail because of a CI issue, a registry timeout, a secret misconfiguration, a networking rule, or a scaling limit.</p>
<p>Each lives in a different system. Each requires different context.</p>
<p>Individually, these tools are well-designed. Collectively, they form a system that's hard to reason about under pressure.</p>
<h2 id="heading-this-model-breaks-as-you-scale">This Model Breaks as You Scale</h2>
<p>This only works while your system is small. But production systems don't stay small.</p>
<p>More services mean more pipelines. More configurations. More failure points.</p>
<p>Over time, the effort required to maintain your deployment system grows faster than the product itself.</p>
<p>That is the inflection point: where engineering time shifts away from building features and toward maintaining the machinery that ships them.</p>
<p>If you're already feeling that shift, it's not temporary. It's structural.</p>
<p>At some point, there's a question that becomes hard to ignore: Why are you still managing this yourself?</p>
<p>Not because you can't. But because it's no longer clear that you should.</p>
<h2 id="heading-the-shift-toward-platforms">The Shift Toward Platforms</h2>
<p>This is where <a href="https://www.freecodecamp.org/news/from-metrics-to-meaning-how-paas-helps-developers-understand-production/">Platform as a Service</a> changes the model. Not by adding more tools, but by taking ownership of the system those tools create.</p>
<p>A PaaS defines a path from code to production. That path is opinionated, constrained, and consistent.</p>
<p>Those constraints aren't limitations. They're what remove entire categories of failure.</p>
<p>Instead of assembling a deployment pipeline, you adopt one.</p>
<h2 id="heading-what-you-stop-paying-for">What You Stop Paying For</h2>
<p>Moving to a PaaS is often framed as convenience. For production teams, it's closer to cost removal.</p>
<p>You stop spending time deciding how builds run, how services are exposed, how scaling is configured, and how logs are collected.</p>
<p>You stop debugging the integration points between those decisions. You trade flexibility for predictability.</p>
<p>And for most teams, predictability is the constraint that actually matters.</p>
<h2 id="heading-from-infrastructure-work-back-to-product-work">From Infrastructure Work Back to Product Work</h2>
<p>The biggest change isn't in your architecture. It's in your allocation of engineering effort.</p>
<p>Time spent debugging deploys shifts back to building features. Time spent maintaining pipelines shifts to improving the product.</p>
<p>Deploys become routine again. Not because they're simpler in theory, but because the system around them is controlled.</p>
<h2 id="heading-collapsing-the-stack">Collapsing the Stack</h2>
<p>The advantage of a PaaS isn't abstraction. It's consolidation.</p>
<p>Build, deploy, runtime, and observability are integrated into a single system.</p>
<p>There are fewer layers to coordinate. Fewer places to look when something fails. And fewer decisions to get wrong.</p>
<p>Platforms like <a href="https://sevalla.com/">Sevalla</a>, Railway, and Render are pushing this further by tightening the loop between code and production, reducing both the number of systems involved and the surface area developers need to understand.</p>
<p>The goal is operational clarity.</p>
<h2 id="heading-the-trade-off-you-are-actually-making">The Trade-Off You Are Actually Making</h2>
<p>The common objection is control. And it's valid. You give up the ability to customize every layer of your infrastructure.</p>
<p>But in practice, most teams aren't using that control to create differentiation. They're using it to keep a fragile system running, and it’s what keeps teams stuck maintaining systems they shouldn’t own.</p>
<p>Every custom configuration adds another failure point. Another dependency. Another thing to maintain under pressure.</p>
<p>The trade-off isn't control versus convenience. It's control versus reliability.</p>
<h3 id="heading-when-this-becomes-urgent">When This Becomes Urgent</h3>
<p>You don't need a major outage to justify a change. The signals show up earlier.</p>
<p>Deploys feel unpredictable. Releases slow down. Engineers spend more time on pipelines than product logic. Onboarding takes longer than it should.</p>
<p>These aren't isolated issues. They are indicators that your current model isn't scaling with your system.</p>
<h2 id="heading-when-managing-infra-still-makes-sense">When Managing Infra Still Makes Sense</h2>
<p>A PaaS may not right for every team.</p>
<p>If your app is still small, deployments are smooth, and your team isn't spending much time on infrastructure, you may not need a PaaS yet.</p>
<p>Some large companies also choose to build and manage their own platforms. For them, infrastructure is an important part of the business, so the extra work is worth it.</p>
<p>The important thing is making that choice on purpose.</p>
<p>Managing infrastructure is not always a bad thing. The real problem starts when app teams slowly take on platform work without enough people, clear ownership, or the right experience to handle it well.</p>
<h3 id="heading-what-a-simple-deploy-actually-means">What a “Simple Deploy” Actually Means</h3>
<p>A simple deploy isn't one that feels easy when everything works. It's one that continues to work as your system grows.</p>
<p>It's predictable. Failures are rare. When they happen, they're easy to diagnose.</p>
<p>And most importantly, it doesn't require your engineers to think about infrastructure to ship code.</p>
<p>That outcome isn't achieved by adding more tools. It's achieved by reducing the system you have to manage.</p>
<h2 id="heading-closing-thought">Closing Thought</h2>
<p>Your deploy didn't turn into a week of infrastructure work because you missed something. It turned into that because you're operating a model that expects you to.</p>
<p>You can continue investing in that model. Or you can adopt one where deploying is a solved problem.</p>
<p>For production teams, that's no longer a philosophical choice. It's an operational one.</p>
<p><em>Join my</em> <a href="https://applyaito.substack.com/"><em><strong>Applied AI newsletter</strong></em></a> <em>to learn how to build and ship real AI systems. Practical projects, production-ready code, and direct Q&amp;A. You can also</em> <a href="https://www.linkedin.com/in/manishmshiva/"><em><strong>connect with me on</strong></em> <em><strong>LinkedIn</strong></em></a><em><strong>.</strong></em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ From Metrics to Meaning: How PaaS Helps Developers Understand Production ]]>
                </title>
                <description>
                    <![CDATA[ Modern production systems generate more data than most developers can realistically process. Every request emits logs. Every service exports metrics. Every dependency introduces another layer of signa ]]>
                </description>
                <link>https://www.freecodecamp.org/news/from-metrics-to-meaning-how-paas-helps-developers-understand-production/</link>
                <guid isPermaLink="false">69ea4e46904b91543899894d</guid>
                
                    <category>
                        <![CDATA[ PaaS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ infrastructure ]]>
                    </category>
                
                    <category>
                        <![CDATA[ metrics ]]>
                    </category>
                
                    <category>
                        <![CDATA[ production ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Thu, 23 Apr 2026 16:52:22 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/e30cdb93-e709-4f28-89fc-ba004735e400.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Modern production systems generate more data than most developers can realistically process.</p>
<p>Every request emits logs. Every service exports metrics. Every dependency introduces another layer of signals.</p>
<p>In theory, this should make systems easier to understand. In practice, it does the opposite.</p>
<p>Dashboards become dense, alerts become noisy, and when something breaks, the same questions still come up: What's actually wrong? Who's affected? Where do you even start?</p>
<p>The problem isn't observability. It's interpretation.</p>
<p>Most teams aren't short on metrics. They're short on meaning.</p>
<p>And that gap exists because developers are often forced to reason about infrastructure when they should be focused on application behaviour.</p>
<p>Metrics exist to describe systems, but without the right level of abstraction, they become another layer of complexity.</p>
<p>This is where modern PaaS platforms change the equation. They don't remove metrics. Instead, they turn them into signals that developers can actually use.</p>
<p>This article breaks down five metrics that consistently matter in production systems. More importantly, it shows how a PaaS helps translate these metrics into something actionable, without requiring developers to act as infrastructure operators.</p>
<p>I’ll be using the <a href="https://sevalla.com/">Sevalla</a> dashboard to explain these metrics, but other platforms like Railway and Render will have similar metrics.</p>
<h3 id="heading-what-well-cover">What We'll Cover:</h3>
<ul>
<li><p><a href="#heading-what-a-paas-actually-does">What a PaaS Actually Does</a></p>
</li>
<li><p><a href="#heading-latency-becomes-a-clear-performance-signal">Latency Becomes a Clear Performance Signal</a></p>
</li>
<li><p><a href="#heading-error-rate-becomes-a-reliable-indicator-of-failure">Error Rate Becomes a Reliable Indicator of Failure</a></p>
</li>
<li><p><a href="#heading-throughput-becomes-context-instead-of-a-problem">Throughput Becomes Context Instead of a Problem</a></p>
</li>
<li><p><a href="#heading-resource-utilisation-moves-out-of-the-critical-path">Resource Utilisation Moves Out of the Critical Path</a></p>
</li>
<li><p><a href="#heading-instance-health-becomes-invisible-by-design">Instance Health Becomes Invisible by Design</a></p>
</li>
<li><p><a href="#heading-from-metrics-to-meaning">From Metrics to Meaning</a></p>
</li>
<li><p><a href="#heading-why-this-matters-for-developers">Why This Matters for Developers</a></p>
</li>
<li><p><a href="#heading-the-real-advantage-is-clarity">The Real Advantage Is Clarity</a></p>
</li>
</ul>
<h2 id="heading-what-a-paas-actually-does">What a PaaS Actually Does</h2>
<p>A Platform as a Service (PaaS) is an abstraction layer over infrastructure that handles deployment, scaling, networking, and runtime management for you.</p>
<p>Instead of provisioning servers, configuring load balancers, and setting up autoscaling rules, you deploy your application and the platform takes care of how it runs in production.</p>
<p>Platforms like Sevalla, Railway, and Render operate on this model. The key shift is responsibility.</p>
<p>In a traditional setup, developers are responsible for both application behaviour and infrastructure behaviour. If latency spikes or errors increase, you have to determine whether the issue is in your code, your scaling rules, or the underlying system.</p>
<p>A PaaS moves most of that infrastructure responsibility into the platform.</p>
<p>You still get access to metrics, but many of the variables behind those metrics –instance lifecycle, scaling decisions, resource allocation –&nbsp;are handled automatically.</p>
<p>This changes how you interpret what you see.</p>
<p>Metrics stop being signals that require cross-layer investigation, and start becoming signals that map more directly to application behaviour.</p>
<p>Now let's see what can happen if your team switches to using a PaaS.</p>
<h2 id="heading-latency-becomes-a-clear-performance-signal"><strong>Latency Becomes a Clear Performance Signal</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/66c6d8f04fa7fe6a6e337edd/4b0ed69b-d122-497c-9cd4-ad8d7b29584a.webp" alt="Latency graph" style="display:block;margin:0 auto" width="1535" height="410" loading="lazy">

<p>Latency is the most direct representation of user experience. It tells you how long your system takes to respond.</p>
<p>When latency increases, users feel it immediately. Pages slow down. APIs become unreliable. Even small delays impact engagement.</p>
<p>Most developers know to look at percentiles like p95 or p99 instead of averages. The slowest requests are what define perceived performance.</p>
<p>But in many environments, understanding latency isn't straightforward.</p>
<p>A spike could come from inefficient code. Or from cold starts. Or from scaling delays. Or from network routing issues. Developers are forced to investigate layers they didn't build.</p>
<p>This is where a PaaS changes the role of latency.</p>
<img src="https://cdn.hashnode.com/uploads/covers/66c6d8f04fa7fe6a6e337edd/d22aac3e-5a50-4f6c-baa9-63afc388da54.webp" alt="Speed metrics" style="display:block;margin:0 auto" width="1536" height="562" loading="lazy">

<p>Instead of being a starting point for infrastructure debugging, latency becomes a clean signal of application performance. Scaling, routing, and resource allocation are handled by the platform. What remains is a clearer relationship between code and outcome.</p>
<p>When latency increases, developers can focus on what they actually control: queries, logic, and dependencies.</p>
<p>The metric stays the same. The meaning becomes clearer.</p>
<h2 id="heading-error-rate-becomes-a-reliable-indicator-of-failure"><strong>Error Rate Becomes a Reliable Indicator of Failure</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/66c6d8f04fa7fe6a6e337edd/664b6eab-f43d-4aec-a412-825d0c7c060b.webp" alt="Error rate graph" style="display:block;margin:0 auto" width="1226" height="288" loading="lazy">

<p>Error rate answers a simple question. Is the system working or not?</p>
<p>It's usually measured as the percentage of requests that fail due to server-side issues. These are failures users can't recover from. A broken checkout flow or a failed API call directly impacts trust.</p>
<p>In theory, error rate should be one of the easiest metrics to act on. In practice, it rarely is.</p>
<p>Errors can come from application bugs, but also from timeouts, resource limits, failed deployments, or unstable instances. Developers end up correlating errors with infrastructure events just to understand what happened.</p>
<p>This slows everything down.</p>
<p>A PaaS reduces this ambiguity.</p>
<p>Failures caused by scaling, instance crashes, or transient infrastructure issues are handled at the platform level. Retries, isolation, and recovery mechanisms are built in.</p>
<p>What remains is a tighter link between error rate and application correctness.</p>
<p>When the error rate increases, it's far more likely to be something in the code or a dependency, not an invisible infrastructure issue.</p>
<p>This shifts the error rate from a noisy metric into a reliable signal.</p>
<h2 id="heading-throughput-becomes-context-instead-of-a-problem"><strong>Throughput Becomes Context Instead of a Problem</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/66c6d8f04fa7fe6a6e337edd/045bbee4-8d29-4a9f-a6e7-e235e08bc920.webp" alt="Throughput graph" style="display:block;margin:0 auto" width="1533" height="398" loading="lazy">

<p>Throughput measures how many requests your system handles over time.</p>
<p>It provides context for everything else. Latency and error rate only make sense when you know how much traffic the system is handling.</p>
<p>A spike in latency during high traffic is expected. The same spike during low traffic is a warning sign.</p>
<p>But in many systems, throughput introduces operational complexity. Traffic changes require scaling decisions. Teams define autoscaling rules, tune thresholds, and try to predict demand. When things go wrong, they revisit those decisions.</p>
<p>Developers end up thinking about capacity instead of behaviour.</p>
<p>A PaaS shifts this responsibility. Scaling is automatic. Traffic spikes are absorbed by the platform. Developers don't need to decide how many instances should be running or when to scale.</p>
<p>Throughput becomes what it should be: context.</p>
<p>It helps explain what's happening, without forcing developers to manage how the system adapts.</p>
<h2 id="heading-resource-utilisation-moves-out-of-the-critical-path"><strong>Resource Utilisation Moves Out of the Critical Path</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/66c6d8f04fa7fe6a6e337edd/3636488f-7648-4db8-ae00-1c8374ca46ba.webp" alt="Sytem utilization" style="display:block;margin:0 auto" width="1534" height="517" loading="lazy">

<p>Resource utilization measures how much CPU, memory, and I/O your system consumes.</p>
<p>Traditionally, this has been central to operating systems. High CPU or memory usage signals potential issues. Teams monitor these metrics to avoid failures and plan scaling.</p>
<p>But for most developers, resource utilization isn't where value is created.</p>
<p>Yet in many environments, developers are still responsible for interpreting these signals. They tune memory limits, investigate CPU spikes, and try to optimise resource usage to keep systems stable.</p>
<p>This is operational work.</p>
<p>A PaaS changes the role of these metrics.</p>
<p>Resource management is handled by the platform. Allocation, scaling, and isolation happen automatically. Developers don't need to constantly watch CPU graphs or memory charts to keep the system running.</p>
<p>These metrics still exist, but they move into the background.</p>
<p>They become diagnostic tools rather than primary signals.</p>
<p>Developers can focus on performance at the application level, instead of managing how infrastructure behaves under load.</p>
<h2 id="heading-instance-health-becomes-invisible-by-design"><strong>Instance Health Becomes Invisible by Design</strong></h2>
<img src="https://cdn.hashnode.com/uploads/covers/66c6d8f04fa7fe6a6e337edd/fd4a755d-c90c-45fd-843e-9be5e5f85caf.webp" alt="Instance health" style="display:block;margin:0 auto" width="1544" height="417" loading="lazy">

<p>Instance health tracks restarts, crashes, and lifecycle events.</p>
<p>In many systems, this is a critical metric. Frequent restarts indicate instability. Memory leaks, crashes, or resource exhaustion often show up here first.</p>
<p>Teams monitor instance health to catch issues early and prevent cascading failures.</p>
<p>But this also reveals something important: developers are aware of, and responsible for, the lifecycle of infrastructure. They track restarts, investigate crashes, and try to stabilise the system manually.</p>
<p>A PaaS removes this responsibility.</p>
<p>Unhealthy instances are restarted automatically. Load is redistributed. Capacity is maintained without manual intervention.</p>
<p>Instance health doesn't disappear, but it no longer requires constant attention. It becomes part of the platform’s internal behaviour, not something developers need to actively manage.</p>
<h2 id="heading-from-metrics-to-meaning"><strong>From Metrics to Meaning</strong></h2>
<p>These five metrics haven't changed.</p>
<p>Latency still reflects performance. Error rate still reflects correctness. Throughput still reflects demand. Resource utilization still reflects efficiency. Instance health still reflects stability.</p>
<p>What changes is how much work it takes to interpret them.</p>
<p>In lower-level environments, developers have to connect these signals themselves. A latency spike leads to checking throughput, then resource usage, then instance behaviour. Each step requires context, assumptions, and time.</p>
<p>This is where complexity accumulates.</p>
<p>A PaaS reduces that gap.</p>
<p>It handles scaling, recovery, and resource management so that metrics map more directly to application behaviour. The signals become easier to interpret because fewer variables are exposed.</p>
<p>Instead of asking multiple questions across layers, developers can move more directly from symptom to cause.</p>
<h2 id="heading-why-this-matters-for-developers"><strong>Why This Matters for Developers</strong></h2>
<p>Most developers don't want to manage infrastructure. They want to build features, ship improvements, and respond to user needs.</p>
<p>But as systems grow, operational responsibility expands. Monitoring becomes more complex. Debugging requires more context. A significant portion of time shifts from building to maintaining.</p>
<p>Metrics are part of this shift.</p>
<p>They're necessary, but they also reflect how much of the system you're responsible for understanding.</p>
<p>A PaaS doesn't eliminate metrics. It reduces the effort required to make sense of them.</p>
<p>It ensures that when something changes in production, the signals developers see are closer to the reality they care about: application behaviour. User experience. System correctness.</p>
<h2 id="heading-the-real-advantage-is-clarity"><strong>The Real Advantage Is Clarity</strong></h2>
<p>The goal is not to have fewer metrics.</p>
<p>It's to have metrics that mean something without requiring deep infrastructure reasoning.</p>
<p>These five metrics form a complete picture of system health. But their real value depends on how directly they map to what developers control.</p>
<p>The more layers you have to think about, the harder mapping becomes.</p>
<p>A good PaaS removes those layers. It turns metrics from raw data into usable signals.</p>
<p>And that shift from metrics to meaning is what allows developers to understand production systems without being buried under them.</p>
<p><em>Join my</em> <a href="https://applyaito.substack.com/"><em><strong>Applied AI newsletter</strong></em></a> <em>to learn how to build and ship real AI systems. Practical projects, production-ready code, and direct Q&amp;A. You can also</em> <a href="https://www.linkedin.com/in/manishmshiva/"><em><strong>connect with me on</strong></em> <em><strong>LinkedIn</strong></em></a><em><strong>.</strong></em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ VPS vs PaaS: How to Choose a Hosting Solution ]]>
                </title>
                <description>
                    <![CDATA[ If you’ve ever stared at a dozen hosting plans, not sure which one to choose, you’re not alone. Hosting isn’t one-size-fits-all, and knowing the difference between a VPS (Virtual Private Server) and a PaaS (Platform as a Service) can help you pick so... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/vps-vs-paas-how-to-choose-a-hosting-solution/</link>
                <guid isPermaLink="false">687fca00b102539f23984a03</guid>
                
                    <category>
                        <![CDATA[ hosting ]]>
                    </category>
                
                    <category>
                        <![CDATA[ server ]]>
                    </category>
                
                    <category>
                        <![CDATA[ PaaS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Cloud Computing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Tue, 22 Jul 2025 17:27:28 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753205132683/65ed718f-a68e-4e31-8db3-cf9265e50817.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you’ve ever stared at a dozen hosting plans, not sure which one to choose, you’re not alone. Hosting isn’t one-size-fits-all, and knowing the difference between a VPS (Virtual Private Server) and a PaaS (Platform as a Service) can help you pick something that works for your project.</p>
<p>Let’s break them down clearly. We’ll go through VPS and PaaS in detail in terms of scaling, pricing, control, and so on. Each handles hosting very differently, and by the end of this guide, you’ll know exactly which solution fits your workflow better.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-a-vps">What is a VPS?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-a-paas">What is a PaaS?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-control-and-customization">Control and Customisation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-setup-and-deployment">Setup and Deployment</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-scaling">Scaling</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-maintenance-and-updates">Maintenance and Updates</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-performance">Performance</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-security">Security</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-pricing">Pricing</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-when-to-use-each">When to Use Each</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-summary">Summary</a></p>
</li>
</ul>
<h2 id="heading-what-is-a-vps">What is a VPS?</h2>
<p>VPS stands for <a target="_blank" href="https://cloud.google.com/learn/what-is-a-virtual-private-server">Virtual Private Server</a>. Think of it as your own slice of a physical server.</p>
<p>Unlike shared hosting, where you compete for resources, a VPS gives you isolated computing power, dedicated RAM, CPU, and storage that’s all yours.</p>
<p>It acts like a mini datacenter. You gain root access, allowing you to install any OS (such as Ubuntu or CentOS), run custom applications, set up cron jobs, configure firewall rules, and essentially shape the environment as you see fit. It’s flexible, affordable, and powerful, and ideal for developers who want control without the complexity of managing bare-metal hardware.</p>
<h2 id="heading-what-is-a-paas">What is a PaaS?</h2>
<p>PaaS stands for <a target="_blank" href="https://azure.microsoft.com/en-us/resources/cloud-computing-dictionary/what-is-paas">Platform as a Service</a>. It’s a cloud-based environment that lets you build, deploy, and scale applications without worrying about infrastructure.</p>
<p>Instead of provisioning servers or managing software stacks, you simply write your code, connect your Git repository, and hit deploy. The platform takes care of everything from building your app, routing traffic, provisioning SSL, scaling services, and monitoring health. It’s DevOps on autopilot.</p>
<p>PaaS solutions are built for speed and simplicity. They support modern languages and frameworks out of the box and offer smart features like auto-scaling, built-in CI/CD, and usage-based pricing.</p>
<p>Now let’s look at the main differences between the two options so you can decide which is best for your use case.</p>
<h2 id="heading-control-and-customisation"><strong>Control and Customisation</strong></h2>
<p>A VPS gives you full control. It’s your server, your rules. </p>
<p>You get root access, pick your OS, install whatever software you need, and tweak system settings to your liking. VPS solutions makes this easy by letting you deploy clean server images quickly like Ubuntu, Debian, Redhat or whatever suits you. Then it’s all in your hands.</p>
<p>PaaS, on the other hand, limits a bit of that flexibility in exchange for convenience. PaaS abstracts the system layer away completely and often comes with support which is handy if you need help. </p>
<p>You write code, push to a Git repo, and it takes care of the rest. It supports popular languages and frameworks, but if you need a very specific runtime or library, you might hit a wall.</p>
<p>If you like being in control, VPS wins here. If you’d rather avoid infrastructure altogether, PaaS is your solution. </p>
<h2 id="heading-setup-and-deployment"><strong>Setup and Deployment</strong></h2>
<p>Getting a VPS up and running takes more effort. You’ll start by provisioning a server, then SSH in to install packages, configure firewalls, set up your web server, and deploy your code manually or via tools like <a target="_blank" href="https://www.freecodecamp.org/news/the-docker-handbook/">Docker</a>.</p>
<p>With PaaS, setup is nearly instant. You connect your GitHub or GitLab account, select your repo, and click deploy. It handles building, routing, SSL certificates, and launching the app, all within minutes. No SSH, no terminal commands, no surprises.</p>
<p>So if you want fast and repeatable deployments, PaaS is the smoother ride. If you’re okay spending more time upfront to craft your ideal setup, VPS gives you the flexibility.</p>
<h2 id="heading-scaling"><strong>Scaling</strong></h2>
<p>Scaling is one of the biggest advantages of PaaS. When your app traffic increases, it can spin up more containers or instances automatically. </p>
<p>You don’t have to predict resource needs ahead of time. Your app scales with demand and scales back down to save money when things quiet down.</p>
<p>With a VPS, scaling is more manual. You have to monitor usage and upgrade your server or configure load balancers yourself. Some developers enjoy this level of control, especially when optimising resource use. But it can be a headache during unexpected traffic spikes.</p>
<p>If your app is likely to grow or experience unpredictable load, PaaS gives you peace of mind. If your traffic is steady and predictable, VPS can handle it just fine, especially if you’re comfortable managing the growth yourself.</p>
<h2 id="heading-maintenance-and-updates"><strong>Maintenance and Updates</strong></h2>
<p>VPS means you’re in charge of everything under the hood. That includes system updates, security patches, disk usage, and log rotation. You also need to manage backups, monitoring, and anything else that keeps your app healthy and online.</p>
<p>PaaS removes that burden. The platform takes care of OS-level updates, security patches, and even restarts or auto-heals when something goes wrong. You get built-in monitoring and automatic backups, and logs are available right from the dashboard.</p>
<p>If maintenance isn’t your strong suit, or just not how you want to spend your valuable time, PaaS clearly comes out ahead.</p>
<h2 id="heading-performance"><strong>Performance</strong></h2>
<p>With a VPS, you get guaranteed resources. They offers dedicated CPU cores and RAM that only your apps use. You can fine-tune performance at every level, from <a target="_blank" href="https://www.freecodecamp.org/news/the-nginx-handbook/">Nginx</a> config files to memory usage. But I would recommend that you read the provider’s fine print and service terms as dedicated resources are not always fully dedicated.</p>
<p>PaaS solutions often run apps in shared or containerised environments. They manage performance for you and isolate workloads, but you might not have the same raw consistency as with a dedicated VPS, especially under heavy compute loads.</p>
<p>For apps that demand consistent high performance, like an online streaming service, a VPS is often the better choice. For most typical web apps, PaaS delivers more than enough speed and stability.</p>
<h2 id="heading-security"><strong>Security</strong></h2>
<p>In a VPS, security is your responsibility. That includes setting up firewalls, securing SSH access, managing user roles, and keeping the OS up to date. VPS gives you the tools, but it’s up to you to use them correctly.</p>
<p>PaaS handles most security concerns automatically, including <a target="_blank" href="https://www.freecodecamp.org/news/protect-against-ddos-attacks/">DDoS protection</a>. It provides HTTPS out of the box, isolates apps from each other, and keeps the platform patched and hardened. While you’re still responsible for securing your app code, you don’t have to worry about the infrastructure.</p>
<p>If security isn’t your strong point, or you want to reduce risk, PaaS adds a safety net. For experienced sysadmins, VPS offers the flexibility to build your own defenses.</p>
<h2 id="heading-pricing"><strong>Pricing</strong></h2>
<p>VPS pricing may appear more affordable at first glance. A VPS server with 4 GB RAM and 80 GB SSD might only set you back $10-15 per month. But that price is fixed, whether your app is serving ten users or ten thousand. And when you outgrow that plan, scaling means resizing the server or juggling additional machines.</p>
<p>PaaS platforms take a different approach. Instead of paying for fixed resources you may or may not use, you pay for what you actually consume. If your app gets minimal traffic, your costs stay low. But if usage spikes, PaaS scales your resources to match, without downtime or manual effort. You’re billed based on activity, not guesswork.</p>
<p>This makes PaaS a better long-term deal for most modern apps. You’re not locked into static hardware. You don’t have to overpay just to be “safe.” And as your app scales, your infrastructure scales with it automatically. </p>
<p>But keep in mind that since PaaS platforms scale automatically based on demand, a sudden spike in traffic can lead to unexpectedly high costs. To avoid surprise bills, make sure to set up pricing alerts and usage thresholds. Most PaaS providers offer these features to help you stay in control of your budget.</p>
<h2 id="heading-when-to-use-each"><strong>When to Use Each</strong></h2>
<p>Use a VPS if you need complete control, want to host multiple apps on one server, or have special requirements around software, performance, or system-level configuration. </p>
<p><a target="_blank" href="https://www.hetzner.com/">Hetzner</a> is a great choice when you want a solid server at a good price and are comfortable managing it yourself. It offers powerful virtual servers with full root access, making it a favorite among developers who want total control. If you’re comfortable managing your own infrastructure, Hetzner gives you the tools and flexibility to build exactly what you need.</p>
<p>Choose PaaS if you want to move fast, avoid infrastructure headaches, and focus purely on coding. PaaS lets you deploy and scale apps with minimal effort, which makes it ideal for teams that want to spend more time building and growing their business than managing. </p>
<p><a target="_blank" href="https://sevalla.com/">Sevalla</a> is a modern PaaS built for speed and simplicity. It handles everything from deployments to scaling, so you can focus entirely on writing code. With smart usage-based pricing and built-in automation, Sevalla is ideal for developers who want to move fast without managing servers or infrastructure.</p>
<h2 id="heading-summary"><strong>Summary</strong></h2>
<p>There’s no one-size-fits-all answer when choosing between VPS and PaaS. It depends on your priorities, whether you care more about control or convenience, price or speed, flexibility or simplicity.</p>
<p>A VPS gives you a clean slate and full power under the hood. It’s ideal for experienced developers and sysadmins who want to build their environment from the ground up.</p>
<p>A PaaS offering gives you the tools to deploy fast, scale effortlessly, and skip the DevOps. It’s perfect if you’d rather write code than manage servers.</p>
<p>Hope you enjoyed this article. <a target="_blank" href="https://linkedin.com/in/manishmshiva">Connect with me</a> on LinkedIn or <a target="_blank" href="https://manishshivanandhan.com/">visit my website</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build Your Own Heroku with Dokku ]]>
                </title>
                <description>
                    <![CDATA[ By Nuno Bispo Heroku is a well-known PaaS widely used by developers. And as a fun and useful project, you can easily make your own Heroku-like PaaS with Dokku. What is Heroku? Heroku is a platform as a service (PaaS) company founded in 2007. The pla... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-your-on-heroku-with-dokku/</link>
                <guid isPermaLink="false">66d4608a733861e3a22a734b</guid>
                
                    <category>
                        <![CDATA[ Cloud Computing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Docker ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Heroku ]]>
                    </category>
                
                    <category>
                        <![CDATA[ PaaS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 04 Feb 2022 19:01:06 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/02/dokku.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Nuno Bispo</p>
<p>Heroku is a well-known PaaS widely used by developers. And as a fun and useful project, you can easily make your own Heroku-like PaaS with Dokku.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/dokku-logo-with-name5-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-what-is-heroku">What is Heroku?</h2>
<p>Heroku is a platform as a service (PaaS) company founded in 2007. The platform runs on AWS, and its ephemeral storage system is called "Dyno".</p>
<p>Heroku is one of the most used PaaS by developers and for a good reason– it is easy to use, well documented, and supports several programming languages.</p>
<p>But what if you could deploy your own Heroku-like platform, including a CI/CD pipeline, database connections, HTTPS connections, and much more with one simple-to-use application?</p>
<p>Well, that is what Dokku provides and more. Let's take a look.</p>
<h2 id="heading-what-is-a-paas">What is a PaaS?</h2>
<p>Platform-as-a-Service (PaaS) is a software architecture style that provides an easy-to-use abstraction layer for deploying your application's code and managing it.</p>
<p>This allows you to focus on writing business logic rather than worrying about the platform itself.</p>
<p>PaaS providers usually provide their own database service as well as other related services, which can greatly simplify common development tasks.</p>
<p>The great advantage of PaaS is that the application developer doesn't need to perform any system administration work. Instead, you can just upload your code and configuration settings to a central server platform.</p>
<p>The service then takes care of deploying the code, scaling it as needed, backing up data, handling hosting and uptime concerns, and so on.</p>
<h2 id="heading-what-is-dokku">What is Dokku?</h2>
<p>Dokku is a hosted Platform as a Service that enables developers to deploy their applications with ease.</p>
<p>From their website:</p>
<blockquote>
<p>The smallest PaaS implementation you've ever seen</p>
</blockquote>
<p>Dokku is based on Docker and uses Heroku's build-packs to compile and package your applications.</p>
<p>One of the best things about Dokku is that it is very lightweight and can be installed on a single server or VM.</p>
<p>It includes scalable hosting using Docker containers, continuous deployment with Git, and other popular DevOps tools.</p>
<p>Dokku also offers a variety of features, such as support for multiple languages, custom domains, automated deployments, and many more.</p>
<p>You can easily connect Postgres databases and even file storage to your applications.</p>
<p>You can check out more information at <a target="_blank" href="https://dokku.com/">https://dokku.com/</a> or the documentation at: <a target="_blank" href="https://dokku.com/docs/getting-started/installation/">https://dokku.com/docs/getting-started/installation/</a>.</p>
<p>You can also show some love for the <a target="_blank" href="https://github.com/dokku/dokku">open-source GitHub project here</a>. </p>
<h2 id="heading-how-to-install-dokku">How to Install Dokku</h2>
<p>In order to install Dokku you will need a Linux VPS and a domain name. </p>
<p>You can install and use Dokku without a domain name but it is much simpler using a domain. I recommend a cloud VPS because it makes it easier to access and configure.</p>
<p>When connecting a domain, either a single domain or a wildcard can be associated with the server's IP.</p>
<p>I will be using a VPS hosted on <a target="_blank" href="https://hetzner.cloud/">Hetzner</a> with Ubuntu 20.04 installed.</p>
<p>We first start by making sure that our system is up to date with these commands:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Update the linux installation</span>
$ sudo apt update
$ sudo apt upgrade -y
</code></pre>
<p>Then we can download and run the installation script for Dokku:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Install Dokku with the install script</span>
$ wget https://raw.githubusercontent.com/dokku/dokku/v0.26.8/bootstrap.sh;
$ sudo DOKKU_TAG=v0.26.8 bash bootstrap.sh

--&gt; Ensuring we have the proper dependencies
--&gt; Note: Installing dokku <span class="hljs-keyword">for</span> the first time will result <span class="hljs-keyword">in</span> removal of
    files <span class="hljs-keyword">in</span> the nginx <span class="hljs-string">'sites-enabled'</span> directory. Please manually
    restore any files that may be removed after the installation and
    web setup is complete.

    Installation will <span class="hljs-built_in">continue</span> <span class="hljs-keyword">in</span> 10 seconds.

    [...........]

    --&gt; Running post-install dependency installation

 ! Setup a user<span class="hljs-string">'s ssh key for deployment by passing in the public ssh key as shown:

     echo '</span>CONTENTS_OF_ID_RSA_PUB_FILE<span class="hljs-string">' | dokku ssh-keys:add admin</span>
</code></pre>
<p>The installation script will install Docker and all necessary dependencies and also Dokku itself, as seen in the code above.</p>
<p>After the installation is complete we need to assign the SSH keys to access and also configure our domain name.</p>
<p>In case you have set up access to your VPS with SSH (which you should) then you already have the necessary keys – you just need to add them to Dokku:</p>
<pre><code># Assign SSH key to Dokku
$ cat ~<span class="hljs-regexp">/.ssh/</span>authorized_keys | dokku ssh-keys:add admin

<span class="hljs-attr">SHA256</span>:<span class="hljs-number">6</span>O1TLVOUkWV+zmTWXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
</code></pre><p>In case you don't already have an SSH key in the server, then you need to generate a key pair:</p>
<pre><code># Generate SSH key
$ ssh-keygen

Generating public/private rsa key pair.
Enter file <span class="hljs-keyword">in</span> which to save the key (<span class="hljs-regexp">/root/</span>.ssh/id_rsa):
Enter passphrase (empty <span class="hljs-keyword">for</span> no passphrase):
Enter same passphrase again:
Your identification has been saved <span class="hljs-keyword">in</span> /root/.ssh/id_rsa
Your public key has been saved <span class="hljs-keyword">in</span> /root/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:<span class="hljs-number">7</span>T6BbRCVWjGtcSUXXXXXXXXXXXXXXXXXXXXXXXXXXXXX root@freeDokku
The key<span class="hljs-string">'s randomart image is:
+---[RSA 3072]----+
[.................]
|     . oS*.o . . |
[.................]
+----[SHA256]-----+</span>
</code></pre><p>Then you can add it to Dokku:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Add SSH key to Dokku</span>
$ dokku ssh-keys:add admin /root/.ssh/id_rsa.pub

SHA256:7T6BbRCVWjGtcSUXXXXXXXXXXXXXXXXXXXXXXXX
</code></pre>
<p>Next, and the final step, is to assign the domain for your Dokku installation. We do that with the command:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Set installation global domain</span>
$ dokku domains:set-global domain.com

-----&gt; Set domain.com
</code></pre>
<p>Make sure you replace 'domain.com' with your own domain, and that your domain name DNS points to the server's IP address.</p>
<p>And that is all you need to do to install and set up Dokku. It is really that simple.</p>
<p>You can now start adding your applications. </p>
<p>Let's see an example of that by adding a standard Django application in the next section.</p>
<h2 id="heading-how-to-create-your-application-in-dokku">How to Create Your Application in Dokku</h2>
<p>To create and deploy our first application, there is some preparation work we need to do on Dokku.</p>
<p>To deploy an application on Dokku, follow these steps:</p>
<ul>
<li>Create the application on Dokku, which means giving it a name.</li>
<li>Create the associate database (or other plugins, if needed). This will create and provision a database for use with an automatic DATABASE_URL added to the application for ease of deployment.</li>
<li>Push the necessary code to Dokku's application internal GitHub endpoint. This can include also the necessary release steps (like running Django migrations, for example).</li>
</ul>
<p>After the code is pushed, Dokku will generate any necessary Docker container and will run our application with any associated databases (or other plugins).</p>
<p>Now that we've covered the necessary steps, let's go through them in practice.</p>
<p>Let's start by creating our application. For this tutorial, I will create a very simple Django website that contains all the necessary logic for us to test Dokku. </p>
<p>We create an application on Dokku with this command (in the server where we installed Dokku):</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Creating our application on Dokku</span>
$ dokku apps:create djangotutorial

-----&gt; Creating djangotutorial...
</code></pre>
<p>By default, datastores (or databases) are not created when an application is created. </p>
<p>The datastores are handled by a series of plugins. You can <a target="_blank" href="https://dokku.com/docs/community/plugins/#official-plugins-beta">check here for all available plugins</a>.</p>
<p>For our application, we will create a Postgres datastore. Since by default no plugins are installed, we first need to install the Postgres plugin:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># install the postgres plugin</span>
<span class="hljs-comment"># plugin installation requires root, hence the user change</span>
sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git
</code></pre>
<p>Then we can create our Postgres datastore:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Create a Postgres datastore</span>
$ dokku postgres:create djangotutorial_datastore

       Waiting <span class="hljs-keyword">for</span> container to be ready
       Creating container database
       Securing connection to database
=====&gt; Postgres container created: djangotutorial_datastore
=====&gt; djangotutorial_datastore postgres service information
       Config dir:          /var/lib/dokku/services/postgres/djangotutorial_datastore/data
       Config options:
       Data dir:            /var/lib/dokku/services/postgres/djangotutorial_datastore/data
       Dsn:                 postgres://postgres:ea706cc108c805d5124d134d934024c5@dokku-postgres-djangotutorial-datastore:5432/djangotutorial_datastore
       Exposed ports:       -
       Id:                  782a04fe6bbd25958752c17c304358fd5ec1f3c54d6d53175b6481b3b957d94b
       Internal ip:         172.17.0.5
       Links:               -
       Service root:        /var/lib/dokku/services/postgres/djangotutorial_datastore
       Status:              running
       Version:             postgres:14.1
</code></pre>
<p>We can check that our Docker container for the datastore is already up and running with:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Check running containers</span>
$ docker ps

CONTAINER ID   IMAGE                      COMMAND                  CREATED              STATUS              PORTS      NAMES
782a04fe6bbd   postgres:14.1              <span class="hljs-string">"docker-entrypoint.s…"</span>   About a minute ago   Up About a minute   5432/tcp   dokku.postgres.djangotutorial_datastore
</code></pre>
<p>Now that we have the datastore up and running, we need to associate it with our application:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Associate datastore with the application</span>
$ dokku postgres:link djangotutorial_datastore djangotutorial

-----&gt; Setting config vars
       DATABASE_URL:  postgres://postgres:ea706cc108c805d5124d134d934024c5@dokku-postgres-djangotutorial-datastore:5432/djangotutorial_datastore
-----&gt; Restarting app djangotutorial
 !     App image (dokku/djangotutorial:latest) not found
</code></pre>
<p>You can see that a DATABASE_URL is automatically created and associated with the application.</p>
<p>The example above mentions that our application image is not found because we haven't pushed any code to it yet.</p>
<p>We can check our application's environment variables to confirm that our DATABASE_URL is present:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Checking an application environment variables</span>
$ dokku config:show djangotutorial

=====&gt; djangotutorial env vars
DATABASE_URL:  postgres://postgres:ea706cc108c805d5124d134d934024c5@dokku-postgres-djangotutorial-datastore:5432/djangotutorial_datastore
</code></pre>
<p>We now have all the necessary configurations done on the Dokku side to support the deployment of our application.</p>
<p>Next, we will create the code for our application and deploy that to Dokku for an automated CI/CD pipeline.</p>
<h2 id="heading-how-to-create-our-application-code-on-pycharm">How to Create Our Application Code on PyCharm</h2>
<p>Before we can deploy an application, we need to have its source code to push to Dokku.</p>
<p>For this tutorial, we are going to create a very simple Django application that shows also the use of the Postgres database.</p>
<p>We will be using PyCharm as our IDE to create and manage our project.</p>
<p>We create a new project in PyCharm – let's call it 'DjangoTutorial':</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/PyCharm-NewProject.png" alt="Image" width="600" height="400" loading="lazy">
<em>Creating a new project on PyCharm - Screenshot by author</em></p>
<p>I personally prefer to create new projects with a virtual environment already in place, which makes life much easier.</p>
<p>If you created the project with a default main.py file (like I did because I keep forgetting to remove the checkmark), you can safely delete it now. We are not going to use it.</p>
<p>The first step is, of course, to install Django so we can build our application. We do that install using pip:</p>
<pre><code>$ pip install django

Collecting django
  Downloading Django<span class="hljs-number">-4.0</span><span class="hljs-number">.2</span>-py3-none-any.whl (<span class="hljs-number">8.0</span> MB)
     |████████████████████████████████| <span class="hljs-number">8.0</span> MB <span class="hljs-number">6.4</span> MB/s
Collecting sqlparse&gt;=<span class="hljs-number">0.2</span><span class="hljs-number">.2</span>
  Using cached sqlparse<span class="hljs-number">-0.4</span><span class="hljs-number">.2</span>-py3-none-any.whl (<span class="hljs-number">42</span> kB)
Collecting tzdata
  Using cached tzdata<span class="hljs-number">-2021.5</span>-py2.py3-none-any.whl (<span class="hljs-number">339</span> kB)
Collecting asgiref&lt;<span class="hljs-number">4</span>,&gt;=<span class="hljs-number">3.4</span><span class="hljs-number">.1</span>
  Downloading asgiref<span class="hljs-number">-3.5</span><span class="hljs-number">.0</span>-py3-none-any.whl (<span class="hljs-number">22</span> kB)
Installing collected packages: tzdata, sqlparse, asgiref, django
Successfully installed asgiref<span class="hljs-number">-3.5</span><span class="hljs-number">.0</span> django<span class="hljs-number">-4.0</span><span class="hljs-number">.2</span> sqlparse<span class="hljs-number">-0.4</span><span class="hljs-number">.2</span> tzdata<span class="hljs-number">-2021.5</span>
</code></pre><p>Then we create our Django project with:</p>
<pre><code>$ django-admin startproject DjangoTutorial .
</code></pre><p>Notice the '.' at the end of the command. I like to use that so that it creates the project in the current directory instead of creating an extra sub-directory.</p>
<p>You should now have a project structure like this in PyCharm:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/PyCharm-Project.png" alt="Image" width="600" height="400" loading="lazy">
<em>PyCharm folder structure for our Django application - screenshot by the author</em></p>
<p>We can run our project with the standard Django run:</p>
<pre><code>$ python manage.py runserver   

Watching <span class="hljs-keyword">for</span> file changes <span class="hljs-keyword">with</span> StatReloader
Performing system checks...

System check identified no issues (<span class="hljs-number">0</span> silenced).

You have <span class="hljs-number">18</span> unapplied migration(s). Your project may not work properly until you apply the migrations <span class="hljs-keyword">for</span> app(s): admin, auth, contenttypes, sessions.
Run <span class="hljs-string">'python manage.py migrate'</span> to apply them.
February <span class="hljs-number">02</span>, <span class="hljs-number">2022</span> - <span class="hljs-number">16</span>:<span class="hljs-number">49</span>:<span class="hljs-number">27</span>
Django version <span class="hljs-number">4.0</span><span class="hljs-number">.2</span>, using settings <span class="hljs-string">'DjangoTutorial.settings'</span>
Starting development server at http:<span class="hljs-comment">//127.0.0.1:8000/</span>
Quit the server <span class="hljs-keyword">with</span> CTRL-BREAK.
</code></pre><p>We have not yet applied our migrations, so we will do that next after we discuss the database configuration for both local and Dokku access.</p>
<p>Navigating to the link <a target="_blank" href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>, we can now access our standard Django welcome page:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/Django.png" alt="Image" width="600" height="400" loading="lazy">
<em>Django welcome page - screenshot by the author</em></p>
<p>We have our Django installation up and running so now we can start building the rest of the project.</p>
<p>Like most projects, we will need to store data in a database (or database using the Dokku naming).</p>
<p>We also want to be able to debug and run our application locally on the development machine (using a local database, in this SQLite) and run it on the cloud with Dokku using the Postgres database. </p>
<p>This means we need to change some configuration in our settings.py to be able to support both use cases without us needing to change any flags or configs every time.</p>
<p>We start by installing the package dj-database-url with:</p>
<pre><code># Install packages <span class="hljs-keyword">for</span> the database url
$ pip install dj-database-url
$ pip install psycopg2


# We also install <span class="hljs-built_in">this</span> package to be able to use environment variables
$ pip install python-decouple
</code></pre><p>This package enables us to have a Django database connection dictionary, populated with all the data by simply specifying a database URL.</p>
<p>With the package install, let's update the configuration on the settings.py:</p>
<pre><code class="lang-python"><span class="hljs-comment"># We need to add this import at the beginning to use environment variables</span>
<span class="hljs-keyword">import</span> dj_database_url
<span class="hljs-keyword">from</span> decouple <span class="hljs-keyword">import</span> config
<span class="hljs-keyword">from</span> django.conf.global_settings <span class="hljs-keyword">import</span> DATABASES

.....

<span class="hljs-comment"># Let's also updated the allowed host so we can use it later on</span>
ALLOWED_HOSTS = config(<span class="hljs-string">'ALLOWED_HOSTS'</span>).split(<span class="hljs-string">','</span>)

.....

<span class="hljs-comment"># We replace the default database configuration from Django with this one</span>
<span class="hljs-comment"># Database</span>
<span class="hljs-comment"># https://docs.djangoproject.com/en/4.0/ref/settings/#databases</span>

<span class="hljs-comment"># DATABASE URL</span>
DATABASES[<span class="hljs-string">'default'</span>] = dj_database_url.parse(config(<span class="hljs-string">'DATABASE_URL'</span>),conn_max_age=<span class="hljs-number">600</span>)
</code></pre>
<p>We will also need to create '.env' file in the root dir of our project:</p>
<pre><code>#HOST SETTINGS
ALLOWED_HOSTS = <span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>

#DATABASE SETTINGS
DATABASE_URL=<span class="hljs-string">'sqlite:///db.sqlite3'</span>
</code></pre><p>As you can see, with this change we can use the database URL from the local '.env' file on the local development machine, and then on Dokku it will automatically use the already defined DATABASE_URL that was created when we linked the datastore to the application on Dokku.</p>
<p>We can now create our first (and only) web page of this tutorial), a simple counter that stores and read the value from the database.</p>
<p>Let's create a separate application to contain our logic:</p>
<pre><code class="lang-bash">$ python manage.py startapp counter
</code></pre>
<p>We now should have a new folder called 'counter' in our project. Let's add a new model by opening the 'models.py' file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Counter</span>(<span class="hljs-params">models.Model</span>):</span>
    count = models.IntegerField(default=<span class="hljs-number">0</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.count
</code></pre>
<p>We can now add a new URL to load our counter page. We do that by adding a new file called 'urls.py' to our 'counter' folder:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> django.urls <span class="hljs-keyword">import</span> path
<span class="hljs-keyword">from</span> . <span class="hljs-keyword">import</span> views

urlpatterns = [
    path(<span class="hljs-string">'counter/'</span>, views.counter, name=<span class="hljs-string">'counter'</span>),
]
</code></pre>
<p>We now have both the model and the URL to load our test page. All we need now is the view and HTML template to render the page.</p>
<p>Let's create the view by editing the 'views.py' file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> django.shortcuts <span class="hljs-keyword">import</span> render
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Counter


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">counter</span>(<span class="hljs-params">request</span>):</span>
    counter_value = Counter.objects.last()

    <span class="hljs-keyword">if</span> counter_value <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:
        counter_value = Counter(count=<span class="hljs-number">0</span>)
        counter_value.save()

    <span class="hljs-keyword">if</span> request.method == <span class="hljs-string">'POST'</span>:
        counter_value.count += <span class="hljs-number">1</span>
        counter_value.save()

    <span class="hljs-keyword">return</span> render(request, <span class="hljs-string">'counter.html'</span>, {<span class="hljs-string">'counter'</span>: counter_value.count})
</code></pre>
<p>Now we can create our HTML template to show the counter value on the page. We create a new file called 'counter.html' inside a new 'templates' folder:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Counter<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span>&gt;</span>
      {%csrf_token%}
    <span class="hljs-tag">&lt;<span class="hljs-name">h4</span>&gt;</span>Counter value is: {{ counter }}<span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Increase Counter"</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>The last step is to add our newly created application to the 'settings.py' file in order for Django to recognize it:</p>
<pre><code>.....

INSTALLED_APPS = [
    <span class="hljs-string">'counter'</span>,
    <span class="hljs-string">'django.contrib.admin'</span>,
    <span class="hljs-string">'django.contrib.auth'</span>,
    <span class="hljs-string">'django.contrib.contenttypes'</span>,
    <span class="hljs-string">'django.contrib.sessions'</span>,
    <span class="hljs-string">'django.contrib.messages'</span>,
    <span class="hljs-string">'django.contrib.staticfiles'</span>,
]

.....
</code></pre><p>And the URL to our main URLs file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> django.contrib <span class="hljs-keyword">import</span> admin
<span class="hljs-keyword">from</span> django.urls <span class="hljs-keyword">import</span> path, include

urlpatterns = [
    path(<span class="hljs-string">''</span>, include(<span class="hljs-string">'counter.urls'</span>)),
    path(<span class="hljs-string">'admin/'</span>, admin.site.urls),
]
</code></pre>
<p>With all the necessary code and HTML in place, we can now create and run our migrations to create our new model in the database. We first do that on the local server by running:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Create and run migrations</span>
$ python manage.py makemigrations
$ python manage.py migrate

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, counter, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying counter.0001_initial... OK
  Applying sessions.0001_initial... OK
</code></pre>
<p>As you can see, we not only applied the migrations for our new application but we also run the initial migrations for the other Django applications since this was the first time we ran the migrations.</p>
<p>We can again run our server locally and we should be able to access the URL <a target="_blank" href="http://127.0.0.1:8000/counter/">http://127.0.0.1:8000/counter/</a> and increment the counter:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/CounterPage_Local.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Running our counter application - GIF by the author</em></p>
<p>As you can see, reloading the page keeps our counter value, meaning that the value is been stored in the database with our model.</p>
<h2 id="heading-how-to-deploy-our-application-to-dokku">How to Deploy Our Application to Dokku</h2>
<p>We now have a very simple application running with database integration to store our counter value.</p>
<p>We are ready to deploy it to the cloud so we can test it there and make sure our database is also working in the cloud.</p>
<p>Before we do the Git push to deploy the code to Dokku, we need to do some preparation:</p>
<ul>
<li>Install our web server (gunicorn)</li>
<li>Create our requirements file (for our packages)</li>
<li>Create our Procfile (for our deployment commands)</li>
</ul>
<p>Let's start with installing our web server to use in the cloud:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Install our web server</span>
$ pip install gunicorn
</code></pre>
<p>With our packages in place we can now create our requirements file with:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Create requirements file</span>
$ pip freeze &gt; requirements.txt
</code></pre>
<p>Now we need to create the 'Procfile'. This file is used by Dokku to determine which commands to run on deployment and after deployment. </p>
<p>So let's create a new file called 'Procfile' in the root directory with the contents:</p>
<pre><code>web: gunicorn DjangoTutorial.wsgi
<span class="hljs-attr">release</span>: python manage.py migrate
</code></pre><p>We have created two commands for Dokku to run:</p>
<ul>
<li>release – this command is executed on the deployment of our application in Dokku. We use it to migrate our database.</li>
<li>web – this command allows Dokku to know which webserver to run to allow access to the application.</li>
</ul>
<p>Finally, to make sure that we can collect any static files when our code is deployed to Dokku, we need to create a new directory called 'static' on the root directory. Inside we create an empty file called '.gitkeep' (this will allow us to add the directory to the Git repository later).</p>
<p>We also need to add this path for the static files to our 'settings.py' file:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Static files (CSS, JavaScript, Images)</span>
<span class="hljs-comment"># https://docs.djangoproject.com/en/4.0/howto/static-files/</span>

STATIC_URL = <span class="hljs-string">'static/'</span>
STATIC_ROOT = BASE_DIR / <span class="hljs-string">"static"</span>
</code></pre>
<p>Now all the files and logic are in place and we can deploy to Dokku with a standard Git push. Let's check our current file structure:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/PyCharm-FolderStrcuture-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>PyCharm folder structure - screenshot by the author</em></p>
<p>To be able to push our code to Dokku, we need to add our project to a Git repository.</p>
<p>Since we don't want to push all the files from our folder structure to the Dokku git repository, we create a '.gitignore' to exclude certain files and directories. I use the contents of this excellent Gist to populate the file:</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="3cf91616c9f3bbc3d1339adfc707b08a">
        <script src="https://gist.github.com/MOOOWOOO/3cf91616c9f3bbc3d1339adfc707b08a.js"></script></div><p>We can now initialize and commit our code to a Git repository locally:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Initialize repository</span>
$ git init -b main

<span class="hljs-comment"># Add and commit our files</span>
$ git add . &amp;&amp; git commit -m <span class="hljs-string">"initial commit"</span>

[main (root-commit) e77a16a] initial commit
 20 files changed, 438 insertions(+)       
 create mode 100644 .gitignore
 create mode 100644 DjangoTutorial/__init__.py
 create mode 100644 counter/tests.py
 create mode 100644 counter/urls.py
 create mode 100644 counter/views.py
 create mode 100644 db.sqlite3
 create mode 100644 manage.py
 create mode 100644 requirements.txt
</code></pre>
<p>With our repository committed, we can now push it to a remote repository, that is the Dokku Git repository for our application:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Adding our remote repository (replace domain.com with your domain name)</span>
$ git remote add dokku dokku@domain.com:djangotutorial

<span class="hljs-comment"># Time to push our code to the remote repository</span>
$ git push dokku main

Enumerating objects: 34, <span class="hljs-keyword">done</span>.
Counting objects: 100% (34/34), <span class="hljs-keyword">done</span>.
Delta compression using up to 8 threads
Compressing objects: 100% (31/31), <span class="hljs-keyword">done</span>.
Writing objects: 100% (34/34), 11.41 KiB | 402.00 KiB/s, <span class="hljs-keyword">done</span>.
Total 34 (delta 7), reused 0 (delta 0)
-----&gt; Set main to DOKKU_DEPLOY_BRANCH.
-----&gt; Cleaning up...
-----&gt; Building djangotutorial from herokuish
-----&gt; Adding BUILD_ENV to build environment...
       BUILD_ENV added successfully
-----&gt; Python app detected
-----&gt; No Python version was specified. Using the buildpack default: python-3.9.9
       To use a different version, see: https://devcenter.heroku.com/articles/python-runtimes
-----&gt; No change <span class="hljs-keyword">in</span> requirements detected, installing from cache
-----&gt; Installing python-3.9.9
-----&gt; Installing pip 21.3.1, setuptools 57.5.0 and wheel 0.37.0
-----&gt; Installing SQLite3
-----&gt; Installing requirements with pip
       Collecting asgiref==3.5.0
       Downloading asgiref-3.5.0-py3-none-any.whl (22 kB)
       Collecting dj-database-url==0.5.0
       Downloading dj_database_url-0.5.0-py2.py3-none-any.whl (5.5 kB)
       Collecting Django==4.0.2
       Downloading Django-4.0.2-py3-none-any.whl (8.0 MB)
       Collecting gunicorn==20.1.0
       Downloading gunicorn-20.1.0-py3-none-any.whl (79 kB)
       Collecting psycopg2==2.9.3
       Downloading psycopg2-2.9.3.tar.gz (380 kB)
       Preparing metadata (setup.py): started
       Preparing metadata (setup.py): finished with status <span class="hljs-string">'done'</span>
       Collecting python-decouple==3.5
       Downloading python_decouple-3.5-py3-none-any.whl (9.6 kB)
       Collecting sqlparse==0.4.2
       Downloading sqlparse-0.4.2-py3-none-any.whl (42 kB)
       Collecting tzdata==2021.5
       Downloading tzdata-2021.5-py2.py3-none-any.whl (339 kB)
       Building wheels <span class="hljs-keyword">for</span> collected packages: psycopg2
       Building wheel <span class="hljs-keyword">for</span> psycopg2 (setup.py): started
       Building wheel <span class="hljs-keyword">for</span> psycopg2 (setup.py): finished with status <span class="hljs-string">'done'</span>
       Created wheel <span class="hljs-keyword">for</span> psycopg2: filename=psycopg2-2.9.3-cp39-cp39-linux_x86_64.whl size=579484 sha256=9d6a2810a5d766738526d6f411e5e9ce514cce882b6c80a47a13c02dc7529e02
       Stored <span class="hljs-keyword">in</span> directory: /tmp/pip-ephem-wheel-cache-8k0chg5g/wheels/b3/a1/6e/5a0e26314b15eb96a36263b80529ce0d64382540ac7b9544a9
       Successfully built psycopg2
       Installing collected packages: sqlparse, asgiref, tzdata, python-decouple, psycopg2, gunicorn, Django, dj-database-url
       Successfully installed Django-4.0.2 asgiref-3.5.0 dj-database-url-0.5.0 gunicorn-20.1.0 psycopg2-2.9.3 python-decouple-3.5 sqlparse-0.4.2 tzdata-2021.5
-----&gt; $ python manage.py collectstatic --noinput
       128 static files copied to <span class="hljs-string">'/tmp/build/static'</span>.

-----&gt; Discovering process types
       Procfile declares types -&gt; release, web
-----&gt; Releasing djangotutorial...
-----&gt; Checking <span class="hljs-keyword">for</span> predeploy task
       No predeploy task found, skipping
-----&gt; Checking <span class="hljs-keyword">for</span> release task
-----&gt; Executing release task from Procfile: python manage.py migrate
=====&gt; Start of djangotutorial release task (a602cab30) output
       Operations to perform:
         Apply all migrations: admin, auth, contenttypes, counter, sessions
       Running migrations:
         Applying contenttypes.0001_initial... OK
         Applying auth.0001_initial... OK
         Applying admin.0001_initial... OK
         Applying admin.0002_logentry_remove_auto_add... OK
         Applying admin.0003_logentry_add_action_flag_choices... OK
         Applying contenttypes.0002_remove_content_type_name... OK
         Applying auth.0002_alter_permission_name_max_length... OK
         Applying auth.0003_alter_user_email_max_length... OK
         Applying auth.0004_alter_user_username_opts... OK
         Applying auth.0005_alter_user_last_login_null... OK
         Applying auth.0006_require_contenttypes_0002... OK
         Applying auth.0007_alter_validators_add_error_messages... OK
         Applying auth.0008_alter_user_username_max_length... OK
         Applying auth.0009_alter_user_last_name_max_length... OK
         Applying auth.0010_alter_group_name_max_length... OK
         Applying auth.0011_update_proxy_permissions... OK
         Applying auth.0012_alter_user_first_name_max_length... OK
         Applying counter.0001_initial... OK
         Applying sessions.0001_initial... OK
=====&gt; End of djangotutorial release task (a602cab30) output
-----&gt; App Procfile file found
=====&gt; Processing deployment checks
       No CHECKS file found. Simple container checks will be performed.
       For more efficient zero downtime deployments, create a CHECKS file. See https://dokku.com/docs/deployment/zero-downtime-deploys/ <span class="hljs-keyword">for</span> examples
-----&gt; Deploying djangotutorial via the docker-local scheduler...
-----&gt; Deploying web (count=1)
       Attempting pre-flight checks (web.1)
       Waiting <span class="hljs-keyword">for</span> 10 seconds (web.1)
       Default container check successful (web.1)
-----&gt; Deploying release (count=0)
-----&gt; Running post-deploy
-----&gt; Creating new app virtual host file...
-----&gt; Configuring djangotutorial.domain.com...(using built-in template)
-----&gt; Creating http nginx.conf
       Reloading nginx
-----&gt; Renaming containers
       Renaming container djangotutorial.web.1.upcoming-7101 (f8d229ebd8bc) to djangotutorial.web.1
-----&gt; Checking <span class="hljs-keyword">for</span> postdeploy task
       No postdeploy task found, skipping
-----&gt; Updated schedule file
=====&gt; Application deployed:
       http://djangotutorial.domain.com

To domain.com:djangotutorial
 * [new branch]      main -&gt; main
</code></pre>
<p>We have just deployed our application to Dokku. </p>
<p>What just happened? Well, Dokku did a lot of work for us:</p>
<ul>
<li>Installed Python</li>
<li>Installed the requirements</li>
<li>Collected the static files</li>
<li>Performed the migrations</li>
<li>And finally started a gunicorn server to deploy our application </li>
</ul>
<p>If you had a permission error, then your private key should be registered within your local development environment. If you get a <code>permission denied</code> error when pushing, you can register your private key as follows: <code>ssh-add -k ~/&lt;your private key&gt;</code>.</p>
<p>You may also see an error regarding the ALLOWED_HOSTS when accessing the application. In that case, all you need to do is to run the following command on the Dokku server to set the environment variable to the correct value:</p>
<pre><code># <span class="hljs-built_in">Set</span> ALLOWED_HOSTS environment variable (make sure to use your domain name)
$ dokku config:set djangotutorial ALLOWED_HOSTS=djangotutorial.domain.com
</code></pre><p>We can now access and test our application at the above URL:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/PageCounter_Server.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Running our counter application on Dokku - GIF by the author</em></p>
<p>Congratulations, you just deployed your application on Dokku. </p>
<h2 id="heading-how-to-add-ssl-with-lets-encrypt">How to Add SSL with Let's Encrypt</h2>
<p>One final configuration that we can do is to add SSL security to our application by installing a Let's Encrypt SSL certificate.</p>
<p>We can do this very easily on Dokku with the Let's Encrypt plugin:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Install the Let's Encrypt plugin</span>
sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git

<span class="hljs-comment"># Configure the plugin (make sure to replace to your email)</span>
dokku config:<span class="hljs-built_in">set</span> --global DOKKU_LETSENCRYPT_EMAIL=email@domain.com

<span class="hljs-comment"># set a custom domain that you own for your application</span>
dokku domains:<span class="hljs-built_in">set</span> djangotutorial djangotutorial.your.domain.com

<span class="hljs-comment"># Enable Let's Encrypt</span>
dokku letsencrypt:<span class="hljs-built_in">enable</span> djangotutorial

<span class="hljs-comment"># Enable Let's Encrypt auto-renewal</span>
dokku letsencrypt:cron-job --add
</code></pre>
<p>Now we have a more secure application. After all, our counter is very important.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Using a PaaS makes a developer's life easier when building web applications. </p>
<p>You can use hosted PaaS like Heroku and there are many others, so the choice is there.</p>
<p>But there are some main drawbacks:</p>
<ul>
<li>Price – hosted solutions might have limits in terms of database storage or file storage, among others</li>
<li>You don't control the hosting where the PaaS is deployed. Recent examples of AWS shows that not even the biggest hosting is free of problems.</li>
</ul>
<p>You can work around these issues by self-hosting your PaaS.</p>
<p>This allows for more control in terms of pricing. You can use hosting provider like <a target="_blank" href="https://www.digitalocean.com/">Digital Ocean</a>, <a target="_blank" href="https://hetzner.cloud/">Hetzner</a>, and others who have quite cheap VPSs that work perfectly with Dokku.</p>
<p>There are no database limits. The only limits you might have are memory and disk space, but you can always upgrade your VPS for a smaller price than getting a new database at Heroku.</p>
<p>Dokku is easy to install and like we saw. Creating and deploying an application is a 3 step process:</p>
<ul>
<li>Create an application on Dokku</li>
<li>Create a datastore on Dokku (if needed, like Postgres) and link to the application</li>
<li>Deploy your code to Dokku with Git</li>
</ul>
<p>Additionally, you might need to configure some environment variables and SSL certificates, but that is all. </p>
<p>Dokku is really the smallest PaaS implementation.</p>
<p>Full source code for the Django application is available at:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/nunombispo/DjangoTutorial">https://github.com/nunombispo/DjangoTutorial</a></div>
<p>Follow me on Twitter: <a target="_blank" href="https://twitter.com/DevAsService">https://twitter.com/DevAsService</a></p>
<p>Check out my website at: <a target="_blank" href="https://developer-service.io/">https://developer-service.io/</a></p>
<p>Or check out my blog at: <a target="_blank" href="https://blog.developer-service.io/">https://blog.developer-service.io/</a></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
