Blog at Podcast Later

Talk Python in Production Book

A Cloud-Agnostic Guide to Building, Scaling, and Managing Your Own Python Infrastructure

Welcome to Talk Python in Production, a hands-on guide for Python developers determined to master real-world deployment and infrastructure management. Have you ever felt locked into pricey cloud services or struggled with overly complex DevOps configurations? This book's stack-native approach offers a refreshing alternative.

You'll learn to containerize Python apps, secure them with NGINX, tap into CDNs for global performance, and manage everything on a single, powerful server, without sacrificing reliability. Along the way, you'll see exactly how we evolved Talk Python's own web infrastructure over many years of practical deployment experience. This isn't just theory: discover cost-saving tips, real-world examples, and step-by-step tutorials you can put to use right away. By the end, you'll be confident in running your Python applications at scale, with minimal cloud lock-in and maximum control over your technology stack.

Who is this book for?

This book is ideal for Python developers who want:
  • More control over their web application deployments.
  • To reduce reliance on deeply integrated, "cloud-native" services.
  • Hands-on examples for using Docker, NGINX, Python web frameworks, databases, CDNs, and more -- all from a practical "stack-native" perspective.
If you consider yourself comfortable writing Python but find deployment or DevOps a bit intimidating (or overly expensive), Talk Python in Production was written for you.

What does "stack-native" mean?

"Stack-native" is an alternative deployment philosophy to "cloud-native." Instead of outsourcing dozens of microservices to a hyperscale cloud, you run much of your app on a single, powerful server (e.g., via Docker Compose). This keeps the complexity and cost far lower, avoids lock-in, and is typically manageable by a small team -- or even a single developer.

What topics are covered?

  • Early and evolving architectures: Real-world hosting journeys, from small PaaS approaches to robust multi-VM setups.
  • One big server strategy: Why consolidating resources on a powerful VM can outperform many small nodes in practice.
  • Docker & Docker Compose: Practical guides to containerizing Python apps, building images efficiently, and automating deployments.
  • NGINX & Let's Encrypt: Reverse proxy basics, SSL/TLS certificates, and best practices for production traffic and security.
  • Self-hosted services: Tools like Umami (analytics) and Uptime Kuma (monitoring) that you can run yourself instead of paying for cloud solutions.
  • Performance optimization: Setting up caching, using modern Python app servers, integrating a CDN, etc.
  • Migrations & frameworks: Real-life examples of moving between frameworks (Pyramid to Quart) and cloud providers (DigitalOcean to Hetzner).
  • Stack-native philosophy: How to keep your infrastructure streamlined yet powerful and avoid the complexity of deeply "cloud-native" approaches.

How advanced is the content?

The book doesn't assume deep DevOps knowledge. Readers with moderate Python experience, plus some comfort using Linux terminals and basic web deployment concepts, should be able to follow along. It progressively introduces Docker, NGINX, and other tools with concrete, real-world examples. However, it's not a basic "Hello World" tutorial -- it deals with production-scale considerations like security patches, automated deployments, container orchestration, and cost optimization.

Do I need to be an expert in Docker or Linux to benefit?

No. While having some exposure to Docker or Linux server administration helps, the text walks you through setting up and managing a modern Docker-based deployment from scratch. Think of it as a guided tour of these technologies, with best practices and pitfalls explained along the way.

Which Python web frameworks are discussed?

  • Pyramid (historically): The book starts with an older real-world setup to showcase why certain changes became necessary.
  • Quart (Flask's async sibling): Used in the current production setup. The same lessons largely apply to Flask, FastAPI, Django, etc.
  • Other frameworks get honorable mentions (e.g., Django, FastAPI), but the main focus is on the lessons learned migrating from a legacy framework to a modern async-first one.

Does this cover local development setups, testing, or CI/CD?

Yes, but in a real-world, practical context:

  • Local development often uses Docker Compose so you can mirror production behavior.
  • Testing includes tips like using a staging environment or running quick end-to-end checks (e.g., fetching every page in your site's sitemap).
  • CI/CD is mentioned with examples of automating Docker builds, hooking into GitHub, and ensuring you avoid over-reliance on proprietary build pipelines.

Are cloud services completely avoided?

Not entirely. The philosophy is more about reducing lock-in rather than rejecting all cloud hosting:

  • You'll learn how to run a robust application on a single VM from providers like Hetzner or DigitalOcean.
  • Tools like AWS or Azure are touched upon mainly to highlight cost and complexity trade-offs.
  • Services such as CDNs (e.g., Bunny.net) are integrated where they add clear value.

Is this approach production-ready for high-traffic apps?

Yes. The author's real-world infrastructure serves millions of requests per month on a single well-configured server. Chapters detail:

  • How to handle static files and large content via CDNs.
  • Managing spikes in CPU or memory usage with Docker worker processes.
  • The typical stack supports 99.99% uptime and handles large bandwidth for a fraction of typical hyperscaler costs.

What about security and updates?

Security best practices appear throughout:

  • Linux server patching: Schedules and reboot strategies.
  • HTTPS/SSL certificates: Automated via Let's Encrypt.
  • Isolation: Docker-based app partitioning and private networks.
  • Minimal dependencies: Using open-source tools that you fully understand and control.

Will it help me save money on hosting?

Very likely. By avoiding dozens of microservices and serverless functions, you won't be blindsided by unpredictable bills. The book showcases real monthly costs (often under $100) for heavy-traffic sites. It also explores how scaling up typically remains predictable and affordable.

Does the book include code samples or configuration files?

Yes, there are many code snippets, Dockerfiles, docker-compose configs, NGINX configs, etc. You'll learn from real, working configurations and scripts used in production at Talk Python. References to a companion GitHub repository are also provided, letting you adapt and run these examples yourself.

How does this differ from a typical Docker or DevOps book?

  • It's Python-focused. You'll see examples specifically for Python web apps, not just theoretical Docker or Linux usage.
  • It's experience-based. Each chapter is drawn from an actual journey hosting high-traffic Python sites for years, evolving the infrastructure step-by-step.
  • It emphasizes simplicity and ownership over the more common "cloud-native or bust" approach.

Will this help me migrate an existing site or build a new one?

Both. The text features migrations (like moving providers or frameworks) alongside instructions to build fresh Docker-based services. Whether your app is already deployed somewhere or you're starting from scratch, the examples should be relevant and adaptable.

What if I only want to adopt some of the practices?

That's encouraged! You can pick and choose:

  • Containerizing apps? Check.
  • Self-hosted analytics or monitoring? Sure.
  • Or just adopt the single big server approach without certain extras. The book is meant as a buffet of best practices, not an all-or-nothing blueprint.

Will I learn how to handle emergencies or big spikes in traffic?

Yes. The book details:

  • Container-based horizontal scaling (adding more workers).
  • Integrating a CDN to handle large media or static files.
  • Monitoring and alerting via Uptime Kuma or external services.
  • Strategies to quickly patch and reboot servers with minimal downtime.

How can I discuss ideas, ask questions, or share my experience?

There's a GitHub Discussions page in the book's companion repository, plus the author's social links. You can:

  • Post success stories about adopting a stack-native approach.
  • Ask for help configuring your Docker builds or NGINX files.
  • Suggest improvements or share third-party tools that complement the setup.

In a nutshell, why should I read it?

To learn a practical, no-nonsense way to deploy and operate Python applications at scale without drowning in cloud complexity or spiraling costs. You'll come away confident in your ability to:

  • Manage your entire stack on a single affordable VM (or a small cluster if you really need it).
  • Integrate tools like Docker, NGINX, Let's Encrypt, and CDNs in a cohesive workflow.
  • Scale, monitor, and secure your apps while remaining agile and independent of any one cloud vendor.

Read Talk Python in Production online

Chapter 1: Introduction

Welcome to Talk Python in Production! Learn how Talk Python manages a podcast website, SaaS e-commerce platform, and mobile API traffic without overspending or vendor lock-in. We’ll explore best practices for scaling, cost control, and infrastructure reliability, without building our own data center. This chapter sets the stage for an empowering journey into a more self-reliant, efficient way of running Python applications in production. Enjoy the ride!

Chapter 2: What we've tried

We explore how Talk Python outgrew PythonAnywhere and transitioned to dedicated Linux VMs. Starting with a PaaS was ideal for testing podcast waters, but maintenance downtime and limited control prompted the shift. DigitalOcean offered a simpler, more affordable alternative to hyperscale providers like AWS. With eight small VMs running various apps, podcasts, courses, APIs, the approach worked but introduced complexities, especially around updates and reboots. Ultimately, dividing apps across multiple servers didn’t deliver the expected isolation, simplicity, or cost savings. This chapter highlights the lessons learned, paving the way for a more efficient, containerized hosting environment in future chapters.

Chapter 3: Leaving The Cloud - The Small Business Version

Learn how Talk Python escaped the complexity and costs of hyperscale cloud platforms, inspired by David Heinemeier Hansson’s We have left the cloud journey. Instead of maintaining multiple VMs, we consolidated everything into a single, powerful server running Docker and Docker Compose for seamless app isolation and portability. Enjoy a simpler, faster, and cloud-agnostic setup; without rewriting apps for proprietary services or sacrificing performance and reliability.

Chapter 4: One Big Server Rather Than Many Small Ones

See why Talk Python ditched multiple small servers for a single, larger machine with eight vCPUs and 16 GB RAM. Although the total compute power is the same, consolidating everything under one server simplifies updates, as only one machine needs patching, and dramatically increases peak performance. When each web app spikes separately, it can tap into nearly all eight CPUs, rather than being limited to a small VM. This approach provides 4-8x more capacity for critical moments at roughly the same price. Explore how Docker-based isolation still protects each app while allowing full compute sharing and streamlined management.

Chapter 5: Docker, Docker, Docker

In this chapter, learn why Talk Python embraced Docker on one powerful server instead of sprawling cloud services or heavy orchestration. Containers run directly on the host OS, providing near-zero overhead and a simple yet robust architecture. By consolidating everything under a single VM, Talk Python achieves 99.999% uptime and just 19 seconds of monthly downtime, without Kubernetes-level complexity or vendor lock-in. Inspired by self-hosting success stories like Basecamp and Zig, this approach avoids runaway costs, offers effortless portability, and still benefits from the hosting provider's reliable data center. See how 'just Docker Compose' delivers both performance and peace of mind.

Chapter 6: Running on Rust

Learn how Talk Python accelerates its web apps by adopting Granian, a Rust-based HTTP server supporting both WSGI and ASGI. Discover why legacy options like uWSGI have faded and how Granian compares to Gunicorn and Uvicorn in benchmarks. By harnessing Rust’s battle-tested “hyper” library, Granian delivers impressive throughput and low latency—ideal for Python’s I/O-heavy workloads. You’ll also see how multiple worker processes (a “web garden”) help overcome Python’s GIL, ensuring full hardware utilization. Finally, explore how Talk Python’s Docker-based deployment simplifies upgrades, fosters flexibility, and keeps application performance consistently high in production.

Chapter 7: The Unexpected Benefits of Self-Hosting

Discover how self-hosting with Docker Compose opens up a world of simple, flexible add-ons for your Python apps. In this chapter, you’ll learn how Talk Python integrates open-source analytics (Umami) and downtime monitoring (Uptime Kuma) right on the same server, no extra subscriptions or third-party data sharing required. By running these Dockerized services alongside your main application, you’ll gain deeper insight into user behavior and real-time uptime status. Plus, you’ll see how to manage external volumes for persistent data and free yourself from vendor lock-in. Explore thousands of self-hostable solutions at awesome-selfhosted.net and create the ultimate DIY stack.

Chapter 8: Visualizing Servers and Other Tools

Discover practical ways to monitor and manage Dockerized application, even if you’re new to containers. You’ll learn about btop and Glances, two free, feature-rich terminal dashboards that display CPU, memory, disk usage, and running processes, including those inside containers. Next, see how the Docker Cluster Monitor provides a real-time overview of container statuses and resource limits. You’ll also learn to log into a container’s shell, no SSH setup required, and persist logs with volume mappings to tail them from the host. Armed with these tools and techniques, you’ll gain full visibility and control of your self-hosted environment.

Chapter 9: Docker Performance Tips

Uncover practical Docker optimizations for faster Python app builds and deployments. Learn how to reorder Dockerfile commands to leverage layer caching—so small changes (like editing a CSS file) won’t trigger full dependency reinstalls. Explore uv, a tool that quickly fetches Python versions and caches dependencies, while Docker’s --mount option preserves these caches across rebuilds. You’ll also see how a .dockerignore file trims out unneeded files, speeding up image builds. Finally, discover strategies for improving continuous integration times and reducing PyPI overhead, all while creating smaller, more efficient Docker images for your production environment.

Chapter 10: NGINX, Containers, and Let's Encrypt

Discover how Talk Python uses NGINX as a front-line server and reverse proxy for high-performance HTTPS routing. You’ll see exactly how NGINX connects to Python app servers like Granian or Uvicorn, handling SSL, static file serving, and domain routing. Learn how to automate free SSL certificates with Let’s Encrypt and Certbot, even in a locked-down Docker environment. Through example configurations, you’ll gain insights into mapping volumes for certificate management, creating auto-renew cron jobs, and handling multi-domain setups. Explore these approaches to build a secure, flexible, and modern web stack without locking yourself into proprietary cloud services.

Chapter 11: CDNs

Learn how Talk Python accelerates global content delivery by caching static assets and media through Bunny.net’s expansive worldwide network. You’ll see how replicating CSS, JavaScript, images, and even large audio/video files at 119 edge locations slashes latency for users, whether they’re streaming a podcast or loading a web page. Discover how querystring cache-busting ensures zero stale files on deployment, while straightforward billing (just $0.01/GB) keeps costs low. By offloading bandwidth to the CDN, Talk Python’s main server remains responsive. Explore these techniques to deliver a fast, smooth user experience without relying on hyperscale cloud services.

Chapter 12: Example Server Setup

We walk through creating a fully operational production environment on a single Linux cloud server. You’ll learn how to provision a Hetzner VM, secure it with a firewall, install Docker, and build layered images for both Linux- and Python-based containers. Then, see how to deploy a Flask+HTMX app via Granian, wire it into NGINX, and ensure automatic startups with systemd. Finally, you’ll script deployments and updates, simplifying future releases. By following these step-by-step instructions, you’ll get an end-to-end blueprint for running Python web apps on a fully controlled, one-server infrastructure.

Chapter 13: Static Sites and Hugo

You’ll explore how to blend powerful static site generators, such as Hugo, into your existing Python web stack. First, discover Hugo’s flexibility for building non-blog sites (e.g., data-driven pages) from Markdown and CSV files, all without a database or backend server. Then, learn two ways to embed those static files within your Docker/NGINX environment: host them standalone or nest them under routes in existing Flask apps, like /blog or /docs. You’ll also see tips for cross-linking sitemaps so search engines understand your entire site’s structure, even across static and dynamic app sections.

Chapter 14: Picking a Python Web Framework

Discover how Talk Python replaced its aging Pyramid setup with modern, async-capable Quart. Learn why frameworks like Django, FastAPI, and Litestar were strong contenders, but ultimately lost out to the simplicity and popularity of Flask’s ecosystem. Dive into the two-phase migration approach: first rewriting code to use Quart (staying synchronous), then upgrading critical database calls to async/await. You’ll see how this boost in concurrency trimmed response times from 42ms down to single digits, while eliminating legacy bottlenecks. If you’re evaluating Python web frameworks, this chapter offers a behind-the-scenes migration roadmap.

Chapter 15: Sometimes You Should Build It Yourself

Discover why Talk Python chose to develop its own platforms rather than relying on third-party solutions. You’ll see how self-hosting the podcast site, courses, and bespoke integrations benefits both the business and its audience, delivering features like automated YouTube live stream announcements and advertiser dashboards with zero tracking. Beyond that, building your own tech fosters deep coding experience and keeps you in touch with real-world production challenges. While not everything warrants custom development, credit card processing, static sites, and more may benefit from outside tools, owning select parts of your stack can be a game-changer.

Chapter 16: Moving to Hetzner (a Retrospective)

In this chapter, Michael Kennedy recounts Talk Python’s switch from DigitalOcean to Hetzner's new US data center. By migrating 20-plus services and databases, he gained superior CPU speeds, an 8x bandwidth boost, and cost savings of nearly $1,500 annually. You’ll see how server benchmarks and hands-on comparisons revealed Hetzner’s surprisingly affordable and powerful cloud VMs. Michael also explains why modernizing Talk Python’s “one big server” made this move straightforward, just export and re-deploy the containerized infrastructure. If you’ve ever wondered whether hosting abroad might benefit performance and budget, this Hetzner retrospective offers a firsthand look at the decision process.

Chapter 17: Opposite of Cloud-Native Is?

Learn why the "lift-and-shift to your own data center" mindset isn’t a valid counterpoint to hyperscale, microservice-heavy "cloud-native" stacks. Instead, this chapter introduces "stack-native": a philosophy centered on running just enough containers (e.g., Flask, NGINX, Granian, and a database) on one well-chosen VM. It avoids vendor lock-in, scales seamlessly for many real-world apps, and remains fully owned by your small team. You’ll see why this approach, replete with Docker orchestration, custom volumes, and self-hosted databases, achieves the reliability of Kubernetes without the complexity or runaway cloud costs.

Chapter 18: Conclusion

In Chapter 18: Conclusion, we finalize the journey of “stack-native” development, where simplicity, flexibility, and cost-effective ownership are front and center. You’ve seen how to deploy Python apps using Docker, NGINX, container orchestration, and more, all on a single, powerful VM. This approach ensures minimal complexity, straightforward management, and maximum autonomy. Whether you adopt all these practices or adapt only a few, you now have the tools and confidence to run Python in production, without lock-in or unnecessary cloud-native overhead. Stay connected through mkennedy.codes and the book’s GitHub discussions to share your success stories and keep learning!

Talk Python's Mastodon Michael Kennedy's Mastodon