<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: deployment</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/deployment.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2023-04-29T23:54:40+00:00</updated><author><name>Simon Willison</name></author><entry><title>MRSK</title><link href="https://simonwillison.net/2023/Apr/29/mrsk/#atom-tag" rel="alternate"/><published>2023-04-29T23:54:40+00:00</published><updated>2023-04-29T23:54:40+00:00</updated><id>https://simonwillison.net/2023/Apr/29/mrsk/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://mrsk.dev/"&gt;MRSK&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
A new open source web application deployment tool from 37signals, developed to help migrate their Hey webmail app out of the cloud and onto their own managed hardware. The key feature is one that I care about deeply: it enables zero-downtime deploys by running all traffic through a Traefik reverse proxy in a way that allows requests to be paused while a new deployment is going out—so end users get a few seconds delay on their HTTP requests before being served by the replaced application.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/37-signals"&gt;37-signals&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ops"&gt;ops&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/zero-downtime"&gt;zero-downtime&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/traefik"&gt;traefik&lt;/a&gt;&lt;/p&gt;



</summary><category term="37-signals"/><category term="deployment"/><category term="ops"/><category term="zero-downtime"/><category term="traefik"/></entry><entry><title>Quoting Avery Pennarun</title><link href="https://simonwillison.net/2021/Aug/30/avery-pennarun/#atom-tag" rel="alternate"/><published>2021-08-30T05:46:10+00:00</published><updated>2021-08-30T05:46:10+00:00</updated><id>https://simonwillison.net/2021/Aug/30/avery-pennarun/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://twitter.com/apenwarr/status/1432217189860319238"&gt;&lt;p&gt;Unshipped work is inventory and it costs you money as it spoils&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://twitter.com/apenwarr/status/1432217189860319238"&gt;Avery Pennarun&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;&lt;/p&gt;



</summary><category term="deployment"/></entry><entry><title>Running Datasette on DigitalOcean App Platform</title><link href="https://simonwillison.net/2020/Oct/7/datasette-digitalocean-app-platform/#atom-tag" rel="alternate"/><published>2020-10-07T02:52:54+00:00</published><updated>2020-10-07T02:52:54+00:00</updated><id>https://simonwillison.net/2020/Oct/7/datasette-digitalocean-app-platform/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://til.simonwillison.net/til/til/digitalocean_datasette-on-digitalocean-app-platform.md"&gt;Running Datasette on DigitalOcean App Platform&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I spent some time with DigitalOcean’s new App Platform today, which is a Heroku-style PaaS that starts at $5/month. It looks like it could be a really good fit for Datasette. Disk is ephemeral, but if you’re publishing read-only data that doesn’t matter since you can build the SQLite database as part of the deployment and bundle it up in the Docker/Kubernetes container.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/simonw/status/1313673393690959872"&gt;@simonw&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/heroku"&gt;heroku&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/digitalocean"&gt;digitalocean&lt;/a&gt;&lt;/p&gt;



</summary><category term="deployment"/><category term="heroku"/><category term="datasette"/><category term="digitalocean"/></entry><entry><title>Zero Downtime Release: Disruption-free Load Balancing of a Multi-Billion User Website</title><link href="https://simonwillison.net/2020/Aug/5/zero-downtime-release/#atom-tag" rel="alternate"/><published>2020-08-05T03:27:27+00:00</published><updated>2020-08-05T03:27:27+00:00</updated><id>https://simonwillison.net/2020/Aug/5/zero-downtime-release/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://dl.acm.org/doi/abs/10.1145/3387514.3405885"&gt;Zero Downtime Release: Disruption-free Load Balancing of a Multi-Billion User Website&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I remain fascinated by techniques for zero downtime deployment—once you have it working it makes shipping changes to your software so much less stressful, which means you can iterate faster and generally be much more confident in shipping code.&lt;/p&gt;

&lt;p&gt;Facebook have invested vast amounts of effort into getting this right, and their new paper for the ACM SIGCOMM conference goes into detail about how it all works.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/copyconstruct/status/1290199786000244737"&gt;Cindy Sridharan&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/zero-downtime"&gt;zero-downtime&lt;/a&gt;&lt;/p&gt;



</summary><category term="deployment"/><category term="zero-downtime"/></entry><entry><title>Weeknotes: Datasette Cloud and zero downtime deployments</title><link href="https://simonwillison.net/2020/Jan/21/weeknotes-datasette-cloud-and-zero-downtime-deployments/#atom-tag" rel="alternate"/><published>2020-01-21T20:56:46+00:00</published><updated>2020-01-21T20:56:46+00:00</updated><id>https://simonwillison.net/2020/Jan/21/weeknotes-datasette-cloud-and-zero-downtime-deployments/#atom-tag</id><summary type="html">
    &lt;p&gt;Yesterday's piece on &lt;a href="https://simonwillison.net/2020/Jan/21/github-actions-cloud-run/"&gt;Tracking FARA by deploying a data API using GitHub Actions and Cloud Run&lt;/a&gt; was originally intended to be my weeknotes, but ended up getting a bit too involved.&lt;/p&gt;

&lt;p&gt;Aside from playing with GitHub Actions and Cloud Run, my focus over the past week has been working on Datasette Cloud. Datasette Cloud is the current name I'm using for my hosted &lt;a href="https://datasette.readthedocs.io/"&gt;Datasette&lt;/a&gt; product - the idea being that I'll find it &lt;em&gt;a lot&lt;/em&gt; easier to get &lt;a href="https://simonwillison.net/2019/Sep/10/jsk-fellowship/"&gt;feedback on Datasette from journalists&lt;/a&gt; if they can use it without having to install anything!&lt;/p&gt;

&lt;p&gt;My MVP for Datasette Cloud is that I can use it to instantly provision a new, private Datasette instance for a journalist (or team of journalists) that they can then sign into, start playing with and start uploading their data to (initially as CSV files).&lt;/p&gt;

&lt;p&gt;I have to solve quite a few problems to get there:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Secure, isolated instances of Datasette. A team or user should only be able to see their own files. I plan to solve this using Docker containers that are mounted such that they can only see their own dedicated volumes.&lt;/li&gt;&lt;li&gt;The ability to provision new instances as easily as possible - and give each one its own HTTPS subdomain.&lt;/li&gt;&lt;li&gt;Authentication: users need to be able to register and sign in to accounts. I could use &lt;a href="https://github.com/simonw/datasette-auth-github"&gt;datasette-auth-github&lt;/a&gt; for this but I'd like to be able to support regular email/password accounts too.&lt;/li&gt;&lt;li&gt;Users need to be able to upload CSV files and have them converted into a SQLite database compatible with Datasette.&lt;/li&gt;&lt;/ul&gt;

&lt;h3&gt;Zero downtime deployments&lt;/h3&gt;

&lt;p&gt;I have a stretch goal which I'm taking pretty seriously: I want to have a mechanism in place for zero-downtime deployments of new versions of the software.&lt;/p&gt;

&lt;p&gt;Arguable this is an unneccessary complication for an MVP. I may not fully implement it, but I do want to at least know that the path I've taken is compatible with zero downtime deployments.&lt;/p&gt;

&lt;p&gt;Why do zero downtime deployments matter so much to me? Because they are desirable for rapid iteration, and crucial for setting up continuious deployment. Even a couple of seconds of downtime during a deployment leaves a psychological desire not to deploy too often. I've seen the productivity boost that deploying fearlessly multiple times a day brings, and I want it.&lt;/p&gt;

&lt;p&gt;So I've been doing a bunch of research into zero downtime deployment options (thanks to some &lt;a href="https://twitter.com/simonw/status/1217599189921628160"&gt;great help on Twitter&lt;/a&gt;) and I think I have something that's going to work for me.&lt;/p&gt;

&lt;p&gt;The first ingredient is &lt;a href="https://docs.traefik.io/"&gt;Traefik&lt;/a&gt; - a new-to-me edge router (similar to nginx) which has a delightful focus on runtime configuration based on automatic discovery.&lt;/p&gt;

&lt;p&gt;It works with a bunch of different technology stacks, but I'm going to be using it with regular Docker. Traefik watches for new Docker containers, reads their labels and uses that to reroute traffic to them.&lt;/p&gt;

&lt;p&gt;So I can launch a new Docker container, apply the Docker label &lt;code&gt;"traefik.frontend.rule": "Host:subdomain.mydomain.com"&lt;/code&gt; and Traefik will start proxying traffic to that subdomain directly to that container.&lt;/p&gt;

&lt;p&gt;Traefik also has extremely robust built-in support for Lets Encrypt to issue certificates. I managed to &lt;a href="https://docs.traefik.io/https/acme/#wildcard-domains"&gt;issue a wildcard TLS certificate&lt;/a&gt; for my entire domain, so new subdomains are encrypted straight away. This did require me to give Traefik API access to modify DNS entries - I'm running DNS for this project on Digital Ocean and thankfully Traefik knows how to do this by talking to their API.&lt;/p&gt;

&lt;p&gt;That solves provisioning: when I create a new account I can call the Docker API (from Python) to start up a new, labelled container on a subdomain protected by a TLS certificate.&lt;/p&gt;

&lt;p&gt;I still needed a way to run a zero-downtime deployment of a new container (for example when I release a new version of Datasette and want to upgrade everyone). After quite a bit of research (during which I discovered you can't modify the labels on a Docker container without restarting it) I settled on the approach described in &lt;a href="https://coderbook.com/@marcus/how-to-do-zero-downtime-deployments-of-docker-containers/"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Essentially you configure Traefik to retry failed requests, start a new, updated container with the same routing information as the existing one (causing Traefik to load balance HTTP requests across both), then shut down the old container and trust Traefik to retry in-flight requests against the one that's still running.&lt;/p&gt;

&lt;p&gt;Rudimentary testing with &lt;code&gt;ab&lt;/code&gt; suggested that this is working as desired.&lt;/p&gt;

&lt;p&gt;One remaining problem: if Traefik is running in a Docker container and proxying all of my traffic, how can I upgrade Traefik itself without any downtime?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/simonw/status/1218604019033100288"&gt;Consensus on Twitter&lt;/a&gt; seems to be that Docker on its own doesn't have a great mechanism for this (I was hoping I could re-route port 80 traffic to the host to a different container in an atomic way). But... &lt;code&gt;iptables&lt;/code&gt; has mechanisms that can re-route traffic from one port to another - so I should be able to run a new Traefik container on a different port and re-route to it at the operating system level.&lt;/p&gt;

&lt;p&gt;That's quite enough yak shaving around zero time deployments for now!&lt;/p&gt;

&lt;h3 id="datasette-upload-csvs"&gt;datasette-upload-csvs&lt;/h3&gt;

&lt;p&gt;A big problem I'm seeing with the current Datasette ecosystem is that while Datasette offers a web-based user interface for querying and accessing data, the &lt;a href="https://datasette.readthedocs.io/en/0.33/ecosystem.html#tools-for-creating-sqlite-databases"&gt;tools I've written for actually creating those databases&lt;/a&gt; are decidedly command-line only.&lt;/p&gt;

&lt;p&gt;Telling journalists they have to learn to install and run software on the command-line is way too high a barrier to entry.&lt;/p&gt;

&lt;p&gt;I've always intended to have Datasette plugins that can handle uploading and converting data. It's time to actually build one!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/simonw/datasette-upload-csvs"&gt;datasette-upload-csvs&lt;/a&gt; is what I've got so far. It has a big warning not to use it in the README - it's &lt;em&gt;very&lt;/em&gt; alpha sofware at the moment - but it does prove that the concept can work.&lt;/p&gt;

&lt;p&gt;It uses the &lt;a href="https://datasette.readthedocs.io/en/stable/plugins.html#asgi-wrapper-datasette"&gt;asgi_wrapper&lt;/a&gt; plugin hook to intercept requests to the path &lt;code&gt;/-/upload-csv&lt;/code&gt; and forward them on to another ASGI app, written using Starlette, which provides a basic upload form and then handles the upload.&lt;/p&gt;

&lt;p&gt;Uploaded CSVs are converted to SQLite using &lt;a href="https://sqlite-utils.readthedocs.io/"&gt;sqlite-utils&lt;/a&gt; and written to the first mutable database attached to Datasette.&lt;/p&gt;

&lt;p&gt;It needs a bunch more work (and tests) before I'm comfortable telling people to use it, but it does at least exist as a proof of concept for me to iterate on.&lt;/p&gt;

&lt;h3&gt;datasette-auth-django-cookies&lt;/h3&gt;

&lt;p&gt;No code for this yet, but I'm beginning to flesh it out as a concept.&lt;/p&gt;

&lt;p&gt;I don't particularly want to implement user registration and authentication and cookies and password hashing. I know how to do it, which means I know it's not something you shuld re-roll for every project.&lt;/p&gt;

&lt;p&gt;Django has a really well designed, robust authentication system. Can't I just use that?&lt;/p&gt;

&lt;p&gt;Since all of my applications will be running on subdomains of a single domain, my current plan is to have a regular Django application which handles registration and logins. Each subdomain will then run a custom piece of Datasette ASGI middleware which knows how to read and validate the Django authentication cookie.&lt;/p&gt;

&lt;p&gt;This should give me single sign-on with a single, audited codebase for registration and login with (hopefully) the least amount of work needed to integrate it with Datasette.&lt;/p&gt;

&lt;p&gt;Code for this will hopefully follow over the next week.&lt;/p&gt;

&lt;h3&gt;Niche Museums - now publishing weekly&lt;/h3&gt;

&lt;p&gt;I hit a milestone with my &lt;a href="https://www.niche-museums.com/"&gt;Niche Museums&lt;/a&gt; project: the site now lists details of 100 museums!&lt;/p&gt;

&lt;p&gt;For the 100th entry I decided to celebrate with by far the most rewarding (and exclusive) niche museum experience I've ever had: &lt;a href="https://www.niche-museums.com/browse/museums/100"&gt;Ray Bandar's Bone Palace&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You should read the entry. The short version is that Ray Bandar collected 7,000 animals skulls over a sixty year period, and Natalie managed to score us a tour of his incredible basement mere weeks before the collection was donated to the California Academy of Sciences.&lt;/p&gt;

&lt;img src="https://niche-museums.imgix.net/ray-bandar.jpeg?w=1600&amp;amp;h=800&amp;amp;fit=crop&amp;amp;auto=compress" alt="The basement full of skulls" style="max-width: 100%" /&gt;

&lt;p&gt;Posting one museum a day was taking increasingly more of my time, as I had to delve into the depths of my museums-I-have-visited backlog and do increasing amounts of research. Now that I've hit 100 I'm going to switch to publishing one a week, which should also help me visit new ones quickly enough to keep the backlog full!&lt;/p&gt;

&lt;p&gt;So I only posted four this week:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;a href="https://www.niche-museums.com/browse/museums/97"&gt;The ruins of Llano del Rio&lt;/a&gt; in Los Angeles County&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.niche-museums.com/browse/museums/98"&gt;Cleveland Hungarian Museum&lt;/a&gt; in Cleveland&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.niche-museums.com/browse/museums/99"&gt;New Orleans Historic Voodoo Museum&lt;/a&gt; in New Orleans&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.niche-museums.com/browse/museums/100"&gt;Ray Bandar's Bone Palace&lt;/a&gt; in San Francisco&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;I also &lt;a href="https://github.com/simonw/museums/commits/842dfb96"&gt;built a simple JavaScript image gallery&lt;/a&gt; to better display the 54 photos I published from our trip to Ray Bandar's basement.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/csv"&gt;csv&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/museums"&gt;museums&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/projects"&gt;projects&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/zero-downtime"&gt;zero-downtime&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/docker"&gt;docker&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/weeknotes"&gt;weeknotes&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/traefik"&gt;traefik&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette-cloud"&gt;datasette-cloud&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/digitalocean"&gt;digitalocean&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="csv"/><category term="deployment"/><category term="museums"/><category term="projects"/><category term="zero-downtime"/><category term="docker"/><category term="datasette"/><category term="weeknotes"/><category term="traefik"/><category term="datasette-cloud"/><category term="digitalocean"/></entry><entry><title>How to do Zero Downtime Deployments of Docker Containers</title><link href="https://simonwillison.net/2020/Jan/16/zero-downtime-deployments/#atom-tag" rel="alternate"/><published>2020-01-16T23:12:35+00:00</published><updated>2020-01-16T23:12:35+00:00</updated><id>https://simonwillison.net/2020/Jan/16/zero-downtime-deployments/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://coderbook.com/@marcus/how-to-do-zero-downtime-deployments-of-docker-containers/"&gt;How to do Zero Downtime Deployments of Docker Containers&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I’m determined to get reliable zero-downtime deploys working for a new project, because I know from experience that even a few seconds of downtime during a deploy changes the project mentality from “deploy any time you want” to “don’t deploy too often”. I’m using Docker containers behind Traefik, which means new containers should have traffic automatically balanced to them by Traefik based on their labels. After much fiddling around the pattern described by this article worked best for me: it lets me start a new container, then stop the old one and have Traefik’s “retry” mechanism send any requests to the stopped container over to the new one instead.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/zero-downtime"&gt;zero-downtime&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/docker"&gt;docker&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/traefik"&gt;traefik&lt;/a&gt;&lt;/p&gt;



</summary><category term="deployment"/><category term="zero-downtime"/><category term="docker"/><category term="traefik"/></entry><entry><title>How we use "ship small" to rapidly build new features at GitHub</title><link href="https://simonwillison.net/2020/Jan/2/github-ship-small/#atom-tag" rel="alternate"/><published>2020-01-02T04:30:53+00:00</published><updated>2020-01-02T04:30:53+00:00</updated><id>https://simonwillison.net/2020/Jan/2/github-ship-small/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/mscccc/how-we-use-ship-small-to-rapidly-build-new-features-at-github-5cl9"&gt;How we use &amp;quot;ship small&amp;quot; to rapidly build new features at GitHub&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Useful insight into how GitHub develop new features. They make aggressive use of feature flags, shipping a rough skeleton of a new feature to production as early as possible and actively soliciting feedback from other employees as they iterate on the feature. They static JSON mocks of APIs to unblock their frontend engineers and iterate on the necessary data structures while the real backend is bring implemented.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/webology/status/1212583728310034433"&gt;Jeff Triplett&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/github"&gt;github&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/feature-flags"&gt;feature-flags&lt;/a&gt;&lt;/p&gt;



</summary><category term="deployment"/><category term="github"/><category term="feature-flags"/></entry><entry><title>Azure Readiness Checklist</title><link href="https://simonwillison.net/2019/Oct/26/azure-readiness-checklist/#atom-tag" rel="alternate"/><published>2019-10-26T20:32:46+00:00</published><updated>2019-10-26T20:32:46+00:00</updated><id>https://simonwillison.net/2019/Oct/26/azure-readiness-checklist/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/ghostinthewires/Azure-Readiness-Checklist/blob/master/README.md"&gt;Azure Readiness Checklist&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I love a good comprehensive checklist. This one is focused on large projects running on Azure but it’s still fun to browse through if you are hosting elsewhere, mainly as a reminder of quite how much still goes into deploying large web services into production.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/mipsytipsy/status/1187930078098808832"&gt;Charity Majors&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/azure"&gt;azure&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/checklists"&gt;checklists&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;&lt;/p&gt;



</summary><category term="azure"/><category term="checklists"/><category term="deployment"/></entry><entry><title>Quoting Charity Majors</title><link href="https://simonwillison.net/2018/Aug/27/charity-majors/#atom-tag" rel="alternate"/><published>2018-08-27T21:00:46+00:00</published><updated>2018-08-27T21:00:46+00:00</updated><id>https://simonwillison.net/2018/Aug/27/charity-majors/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://charity.wtf/2018/08/19/shipping-software-should-not-be-scary/amp/?__twitter_impression=true"&gt;&lt;p&gt;In too many organizations, deploy code is a technical backwater, an accumulation of crufty scripts and glue code, forked gems and interns’ earnest attempts to hack up Capistrano.  It usually gives off a strong whiff of “sloppily evolved from many 2 am patches with no code review”.&lt;/p&gt;
&lt;p&gt;This is insane.  Deploy software is the most important software you have.  Treat it that way: recruit an owner, allocate real time for development and testing, bake in metrics and track them over time.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://charity.wtf/2018/08/19/shipping-software-should-not-be-scary/amp/?__twitter_impression=true"&gt;Charity Majors&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/code-review"&gt;code-review&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/charity-majors"&gt;charity-majors&lt;/a&gt;&lt;/p&gt;



</summary><category term="code-review"/><category term="deployment"/><category term="charity-majors"/></entry><entry><title>Quoting Dan Manges</title><link href="https://simonwillison.net/2011/Jun/30/braintree/#atom-tag" rel="alternate"/><published>2011-06-30T21:27:00+00:00</published><updated>2011-06-30T21:27:00+00:00</updated><id>https://simonwillison.net/2011/Jun/30/braintree/#atom-tag</id><summary type="html">
    &lt;blockquote cite="http://www.braintreepayments.com/inside-braintree/how-we-built-the-software-that-processes-billions-in-payments"&gt;&lt;p&gt;We can deploy new versions of our software, make database schema changes, or even rotate our primary database server, all without failing to respond to a single request. We can accomplish this because we gave ourselves the ability suspend our traffic, which gives us a window of a few seconds to make some changes before letting the requests through. To make this happen, we built a custom HTTP server and application dispatching infrastructure around Python’s Tornado and Redis.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="http://www.braintreepayments.com/inside-braintree/how-we-built-the-software-that-processes-billions-in-payments"&gt;Dan Manges&lt;/a&gt;, Braintree&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/http"&gt;http&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/redis"&gt;redis&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/tornado"&gt;tornado&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/recovered"&gt;recovered&lt;/a&gt;&lt;/p&gt;



</summary><category term="deployment"/><category term="http"/><category term="redis"/><category term="tornado"/><category term="recovered"/></entry><entry><title>What to do when PyPI goes down</title><link href="https://simonwillison.net/2010/Jul/21/pypi/#atom-tag" rel="alternate"/><published>2010-07-21T10:19:00+00:00</published><updated>2010-07-21T10:19:00+00:00</updated><id>https://simonwillison.net/2010/Jul/21/pypi/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.jacobian.org/writing/when-pypi-goes-down/#c5203"&gt;What to do when PyPI goes down&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
My deployment scripts tend to rely on PyPI these days (they install dependencies in to a virtualenv) which makes me distinctly uncomfortable. Jacob explains how to use the PyPI mirrors that are starting to come online, but that won’t help if the PyPI listing links to an externally hosted file which starts to 404, as happened with the python-openid package quite recently (now fixed). The comments on the post discuss workarounds, including hosting your own PyPI mirror or bundling tar.gz files of your dependencies with your project.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jacob-kaplan-moss"&gt;jacob-kaplan-moss&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/packaging"&gt;packaging&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pip"&gt;pip&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pypi"&gt;pypi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/setuptools"&gt;setuptools&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/recovered"&gt;recovered&lt;/a&gt;&lt;/p&gt;



</summary><category term="deployment"/><category term="jacob-kaplan-moss"/><category term="packaging"/><category term="pip"/><category term="pypi"/><category term="python"/><category term="setuptools"/><category term="recovered"/></entry><entry><title>Automated deployments with Fabric - tips and tricks</title><link href="https://simonwillison.net/2010/Mar/16/fabric/#atom-tag" rel="alternate"/><published>2010-03-16T11:19:58+00:00</published><updated>2010-03-16T11:19:58+00:00</updated><id>https://simonwillison.net/2010/Mar/16/fabric/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://agiletesting.blogspot.com/2010/03/automated-deployments-with-fabric-tips.html"&gt;Automated deployments with Fabric - tips and tricks&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
“If it’s not in a Fabric fabfile, it’s not deployable”—I’m slowly applying this philosophy to my personal projects.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/fabric"&gt;fabric&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sysadmin"&gt;sysadmin&lt;/a&gt;&lt;/p&gt;



</summary><category term="deployment"/><category term="fabric"/><category term="python"/><category term="sysadmin"/></entry><entry><title>Automate EC2 Instance Setup with user-data Scripts</title><link href="https://simonwillison.net/2010/Mar/11/ec2/#atom-tag" rel="alternate"/><published>2010-03-11T12:31:50+00:00</published><updated>2010-03-11T12:31:50+00:00</updated><id>https://simonwillison.net/2010/Mar/11/ec2/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://alestic.com/2009/06/ec2-user-data-scripts"&gt;Automate EC2 Instance Setup with user-data Scripts&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I knew about EC2’s user-data feature—what I didn’t know is that the Alestic and Canonical images are configured so that if the user-data starts with #! the instance will automatically execute it as a shell script as soon as it boots up (after networking has been configured).

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="http://blog.ianbicking.org/2010/03/10/configuration-management-push-vs-pull/comment-page-1/#comment-155587"&gt;Paul Smith&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ec2"&gt;ec2&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sysadmin"&gt;sysadmin&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/userdata"&gt;userdata&lt;/a&gt;&lt;/p&gt;



</summary><category term="deployment"/><category term="ec2"/><category term="sysadmin"/><category term="userdata"/></entry><entry><title>jacobian's django-deployment-workshop</title><link href="https://simonwillison.net/2010/Feb/19/jacobians/#atom-tag" rel="alternate"/><published>2010-02-19T14:28:35+00:00</published><updated>2010-02-19T14:28:35+00:00</updated><id>https://simonwillison.net/2010/Feb/19/jacobians/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://github.com/jacobian/django-deployment-workshop"&gt;jacobian&amp;#x27;s django-deployment-workshop&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Notes and resources from Jacob’s 3 hour Django deployment workshop at PyCon, including example configuration files for Apache2 + mod_wsgi, nginx, PostgreSQL and pgpool.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/apache"&gt;apache&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jacob-kaplan-moss"&gt;jacob-kaplan-moss&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/modwsgi"&gt;modwsgi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nginx"&gt;nginx&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pgpool"&gt;pgpool&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/postgresql"&gt;postgresql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pycon"&gt;pycon&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sysadmin"&gt;sysadmin&lt;/a&gt;&lt;/p&gt;



</summary><category term="apache"/><category term="deployment"/><category term="django"/><category term="jacob-kaplan-moss"/><category term="modwsgi"/><category term="nginx"/><category term="pgpool"/><category term="postgresql"/><category term="pycon"/><category term="python"/><category term="sysadmin"/></entry><entry><title>Why toppcloud will not be agnostic</title><link href="https://simonwillison.net/2010/Feb/12/toppcloud/#atom-tag" rel="alternate"/><published>2010-02-12T09:21:32+00:00</published><updated>2010-02-12T09:21:32+00:00</updated><id>https://simonwillison.net/2010/Feb/12/toppcloud/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://blog.ianbicking.org/2010/02/10/why-toppcloud-not-agnostic/"&gt;Why toppcloud will not be agnostic&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Ian Bicking’s toppcloud aims to offer deployment with the ease of use of AppEngine against a standard, open source Ubuntu + Python 2.6 + mod_wsgi + Varnish stack. Here he explains why he’s not going to vary the required components: keeping everything completely standardised means everyone gets the same bugs (and the same fixes).


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/google-app-engine"&gt;google-app-engine&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ian-bicking"&gt;ian-bicking&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/modwsgi"&gt;modwsgi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/toppcloud"&gt;toppcloud&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ubuntu"&gt;ubuntu&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/varnish"&gt;varnish&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/wsgi"&gt;wsgi&lt;/a&gt;&lt;/p&gt;



</summary><category term="deployment"/><category term="django"/><category term="google-app-engine"/><category term="ian-bicking"/><category term="modwsgi"/><category term="python"/><category term="toppcloud"/><category term="ubuntu"/><category term="varnish"/><category term="wsgi"/></entry><entry><title>Hot Code Loading in Node.js</title><link href="https://simonwillison.net/2010/Jan/31/liminal/#atom-tag" rel="alternate"/><published>2010-01-31T13:57:53+00:00</published><updated>2010-01-31T13:57:53+00:00</updated><id>https://simonwillison.net/2010/Jan/31/liminal/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://romeda.org/blog/2010/01/hot-code-loading-in-nodejs.html?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A LiminalExistence %28Liminal Existence%29"&gt;Hot Code Loading in Node.js&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Blaine Cook’s patch for Node.js that enables Erlang-style hot code loading, so you can switch out your application logic without restarting the server or affecting existing requests. This could make deploying new versions of Node applications trivial. I’d love to see a Node hosting service that allows you to simply upload a script file and have it execute on the Web.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/blaine-cook"&gt;blaine-cook&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/erlang"&gt;erlang&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;&lt;/p&gt;



</summary><category term="blaine-cook"/><category term="deployment"/><category term="erlang"/><category term="javascript"/><category term="nodejs"/></entry><entry><title>Fabric 0.9.0</title><link href="https://simonwillison.net/2009/Nov/9/fabric/#atom-tag" rel="alternate"/><published>2009-11-09T14:02:53+00:00</published><updated>2009-11-09T14:02:53+00:00</updated><id>https://simonwillison.net/2009/Nov/9/fabric/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://pypi.python.org/pypi/Fabric/0.9.0"&gt;Fabric 0.9.0&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
A Python-based SSH automation and deployment tool. Released today, 0.9.0 is finally the official “stable” release—which is good, as it breaks API compatibility with previous versions and caused me all sorts of confusion when I tried to learn Fabric recently.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/fabric"&gt;fabric&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ssh"&gt;ssh&lt;/a&gt;&lt;/p&gt;



</summary><category term="deployment"/><category term="fabric"/><category term="python"/><category term="ssh"/></entry><entry><title>Automating web site deployment at Barcamp Brighton</title><link href="https://simonwillison.net/2009/Sep/6/automating/#atom-tag" rel="alternate"/><published>2009-09-06T14:16:30+00:00</published><updated>2009-09-06T14:16:30+00:00</updated><id>https://simonwillison.net/2009/Sep/6/automating/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://morethanseven.net/2009/09/06/automating-web-site-deployment-barcamp-brighton/"&gt;Automating web site deployment at Barcamp Brighton&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I’m determined to start using Fabric and proper deployment scripts for my personal projects.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/barcamp"&gt;barcamp&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/barcampbrighton"&gt;barcampbrighton&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/brighton"&gt;brighton&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/fabric"&gt;fabric&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/gareth-rushgrove"&gt;gareth-rushgrove&lt;/a&gt;&lt;/p&gt;



</summary><category term="barcamp"/><category term="barcampbrighton"/><category term="brighton"/><category term="deployment"/><category term="fabric"/><category term="gareth-rushgrove"/></entry><entry><title>Fabric, Django, Git, Apache, mod_wsgi, virtualenv and pip deployment</title><link href="https://simonwillison.net/2009/Jul/28/fabric/#atom-tag" rel="alternate"/><published>2009-07-28T11:56:09+00:00</published><updated>2009-07-28T11:56:09+00:00</updated><id>https://simonwillison.net/2009/Jul/28/fabric/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://morethanseven.net/2009/07/27/fabric-django-git-apache-mod_wsgi-virtualenv-and-p/"&gt;Fabric, Django, Git, Apache, mod_wsgi, virtualenv and pip deployment&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I’m slowly working my way through this stack at the moment—next stop, fabric.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/apache"&gt;apache&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/fabric"&gt;fabric&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/gareth-rushgrove"&gt;gareth-rushgrove&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/git"&gt;git&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/modwsgi"&gt;modwsgi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pip"&gt;pip&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/virtualenv"&gt;virtualenv&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/wsgi"&gt;wsgi&lt;/a&gt;&lt;/p&gt;



</summary><category term="apache"/><category term="deployment"/><category term="django"/><category term="fabric"/><category term="gareth-rushgrove"/><category term="git"/><category term="modwsgi"/><category term="pip"/><category term="python"/><category term="virtualenv"/><category term="wsgi"/></entry><entry><title>Tools of the Modern Python Hacker: Virtualenv, Fabric and Pip</title><link href="https://simonwillison.net/2009/Jul/9/tools/#atom-tag" rel="alternate"/><published>2009-07-09T11:40:58+00:00</published><updated>2009-07-09T11:40:58+00:00</updated><id>https://simonwillison.net/2009/Jul/9/tools/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://clemesha.org/blog/2009/jul/05/modern-python-hacker-tools-virtualenv-fabric-pip/"&gt;Tools of the Modern Python Hacker: Virtualenv, Fabric and Pip&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Ashamed to say I’m not using any of these yet—for Django projects, my manage.py inserts an “ext” directory at the beginning of the Python path which contains my dependencies for that project.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/fabric"&gt;fabric&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pip"&gt;pip&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pythonpath"&gt;pythonpath&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/tools"&gt;tools&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/virtualenv"&gt;virtualenv&lt;/a&gt;&lt;/p&gt;



</summary><category term="deployment"/><category term="django"/><category term="fabric"/><category term="pip"/><category term="python"/><category term="pythonpath"/><category term="tools"/><category term="virtualenv"/></entry><entry><title>Phusion Passenger for nginx</title><link href="https://simonwillison.net/2009/Apr/20/passenger/#atom-tag" rel="alternate"/><published>2009-04-20T04:53:55+00:00</published><updated>2009-04-20T04:53:55+00:00</updated><id>https://simonwillison.net/2009/Apr/20/passenger/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://blog.phusion.nl/2009/04/16/phusions-one-year-anniversary-gift-phusion-passenger-220/"&gt;Phusion Passenger for nginx&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Passenger (aka mod_rails / mod_rack) enables easy deployment of Rails and Ruby apps under Apache... and the latest version adds support for nginx as well. It works as an HTTP proxy and process manager, spawning worker processes and forwarding HTTP requests to them via a request queue. It can also handle Python WSGI applications—anyone tried it out for that yet?


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/apache"&gt;apache&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nginx"&gt;nginx&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/passenger"&gt;passenger&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rails"&gt;rails&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ruby"&gt;ruby&lt;/a&gt;&lt;/p&gt;



</summary><category term="apache"/><category term="deployment"/><category term="nginx"/><category term="passenger"/><category term="python"/><category term="rails"/><category term="ruby"/></entry><entry><title>How to use Django with Apache and mod_wsgi</title><link href="https://simonwillison.net/2009/Apr/1/modwsgi/#atom-tag" rel="alternate"/><published>2009-04-01T00:24:04+00:00</published><updated>2009-04-01T00:24:04+00:00</updated><id>https://simonwillison.net/2009/Apr/1/modwsgi/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://docs.djangoproject.com/en/dev/howto/deployment/modwsgi/"&gt;How to use Django with Apache and mod_wsgi&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
My favourite deployment option is now included in the official Django docs, thanks to Alex Gaynor. I tend to run a stripped down Apache with mod_wsgi behind an nginx proxy, and have nginx serve static files directly. This avoids the need for a completely separate media server (although a separate media domain is still a good idea for better client-side performance).


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/alex-gaynor"&gt;alex-gaynor&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/modwsgi"&gt;modwsgi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nginx"&gt;nginx&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/proxies"&gt;proxies&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/wsgi"&gt;wsgi&lt;/a&gt;&lt;/p&gt;



</summary><category term="alex-gaynor"/><category term="deployment"/><category term="django"/><category term="modwsgi"/><category term="nginx"/><category term="proxies"/><category term="python"/><category term="wsgi"/></entry><entry><title>Webistrano</title><link href="https://simonwillison.net/2007/Aug/31/blogfish/#atom-tag" rel="alternate"/><published>2007-08-31T23:05:54+00:00</published><updated>2007-08-31T23:05:54+00:00</updated><id>https://simonwillison.net/2007/Aug/31/blogfish/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://blog.innerewut.de/webistrano/"&gt;Webistrano&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Web based interface for managing Capistrano deployments. Cal recommends having a “deploy to live site” button in his book; this looks like an easy way to build that.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cal-henderson"&gt;cal-henderson&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/capistrano"&gt;capistrano&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/webistrano"&gt;webistrano&lt;/a&gt;&lt;/p&gt;



</summary><category term="cal-henderson"/><category term="capistrano"/><category term="deployment"/><category term="webistrano"/></entry><entry><title>Quick Django Benching</title><link href="https://simonwillison.net/2007/Feb/17/quick/#atom-tag" rel="alternate"/><published>2007-02-17T16:56:28+00:00</published><updated>2007-02-17T16:56:28+00:00</updated><id>https://simonwillison.net/2007/Feb/17/quick/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://superjared.com/entry/quick-django-benching/"&gt;Quick Django Benching&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Django under Apache/mod_python outperforms nginx/FastCGI and LightTPD/FastCGI once you ramp up the concurrency levels. My setup for this site (Apache/mod_python behind an nginx proxy, with nginx handling static files) should give the best of both worlds.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/apache"&gt;apache&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/fastcgi"&gt;fastcgi&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/lighttpd"&gt;lighttpd&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/modpython"&gt;modpython&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nginx"&gt;nginx&lt;/a&gt;&lt;/p&gt;



</summary><category term="apache"/><category term="deployment"/><category term="django"/><category term="fastcgi"/><category term="lighttpd"/><category term="modpython"/><category term="nginx"/></entry><entry><title>The Django Book: Deploying Django</title><link href="https://simonwillison.net/2007/Jan/26/deploying/#atom-tag" rel="alternate"/><published>2007-01-26T12:38:46+00:00</published><updated>2007-01-26T12:38:46+00:00</updated><id>https://simonwillison.net/2007/Jan/26/deploying/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.djangobook.com/en/beta/chapter21/"&gt;The Django Book: Deploying Django&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Solid advice based on years of experience at the Journal-World and the Washington Post.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/deployment"&gt;deployment&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django-book"&gt;django-book&lt;/a&gt;&lt;/p&gt;



</summary><category term="deployment"/><category term="django"/><category term="django-book"/></entry></feed>