<?xml version="1.0" encoding="utf-8"?>



<feed xmlns="http://www.w3.org/2005/Atom"
    xmlns:fh="http://purl.org/syndication/history/1.0"
    xmlns:at="http://purl.org/atompub/tombstones/1.0">

    <title>Publ: Deployment guides</title>
    <subtitle>A personal publishing system for the modern web</subtitle>
    <link href="https://publ.beesbuzz.biz/manual/deploying/feed" rel="self" />
    <link href="https://publ.beesbuzz.biz/manual/deploying/feed" rel="current" />
    <link href="https://busybee.superfeedr.com" rel="hub" />
    
    
    <link href="https://publ.beesbuzz.biz/manual/deploying/" />
    
    <id>tag:publ.beesbuzz.biz,2020-01-07:manual/deploying</id>
    <updated>2025-05-15T22:38:02-07:00</updated>

    
    <entry>
        <title>Use with Cloudflare or other caching CDNs</title>
        <link href="https://publ.beesbuzz.biz/manual/deploying/675-Use-with-Cloudflare-or-other-caching-CDNs" rel="alternate" type="text/html" />
        <published>2025-05-15T22:38:02-07:00</published>
        <updated>2025-05-15T22:38:02-07:00</updated>
        <id>urn:uuid:b5261c4b-0e8b-517e-b4ed-8c7f5bb4f59b</id>
        <author><name>fluffy</name></author>
        <content type="html">
<![CDATA[
<p>Using Publ with <a href="https://cloudflare.com/">Cloudflare</a> is fairly straightforward, but there are a few things you should keep in mind.</p>

<p>Because of the rise in badly-behaved website scraping bots, it can be very helpful for site performance to have a fronting CDN, such as <a href="https://cloudflare.com/">Cloudflare</a>, in front of your origin server. But there are a few things you need to keep in mind.</p><h3 id="675_h3_1_Caching"><a href="https://publ.beesbuzz.biz/manual/deploying/675-Use-with-Cloudflare-or-other-caching-CDNs#675_h3_1_Caching"></a>Caching</h3><p>When configuring caching, it is very important that you exclude the following paths from any aggressive caching behavior:</p>
<ul>
<li><code>/_cb/</code></li>
<li><code>/_login</code> and <code>/_login/</code></li>
<li><code>/_logout</code> and <code>/_logout/</code></li>
</ul>
<p>If these paths get cached, it may lead to unpredictable behavior for user login and logout.</p><h3 id="675_h3_2_Image-CDN"><a href="https://publ.beesbuzz.biz/manual/deploying/675-Use-with-Cloudflare-or-other-caching-CDNs#675_h3_2_Image-CDN"></a>Image CDN</h3><p>There should be no need for any additional fronting image CDN on Publ, although having it enabled shouldn&rsquo;t hurt. However, because Publ manages its own cache lifetime and the CDN is not aware of this, some strange behaviors may occur in extreme edge cases.</p><p>Setting the CDN to aggressively prefetch images or to use status 103 &ldquo;Early Hints,&rdquo; if possible, is probably a good idea.</p>

]]>
        </content>
    </entry>
    
    <entry>
        <title>Using MySQL/MariaDB as your backing store</title>
        <link href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store" rel="alternate" type="text/html" />
        <published>2024-07-05T11:45:08-07:00</published>
        <updated>2024-07-05T11:45:08-07:00</updated>
        <id>urn:uuid:f9569d5a-44b7-549f-b536-1de795fdd8d7</id>
        <author><name>fluffy</name></author>
        <content type="html">
<![CDATA[
<p>How to use MySQL as the index database</p>

<p>For smaller Publ sites, the suggested configuration is to use <a href="https://sqlite.org/">SQLite</a> for the index database, as it is low-maintenance and performs very well due to being in-process and taking advantage of the operating system&rsquo;s disk cache.</p><p>However, sometimes it&rsquo;s helpful to use a larger-scale database system for the deployment, primarily to gain access to finer-grained locking. This is especially useful in situations where there are many thousands of entries and a desire to keep the site running at full capacity during a reindex.</p><p>Here is a configuration snippet that allows you to use MySQL/MariaDB on your Publ site:</p><figure class="blockcode"><figcaption>app.py</figcaption><pre class="highlight" data-language="python" data-line-numbers><span class="line" id="e764cb1L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L1"></a><span class="line-content"><span class="c1"># ...</span></span></span>
<span class="line" id="e764cb1L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L2"></a><span class="line-content"></span></span>
<span class="line" id="e764cb1L3"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L3"></a><span class="line-content"><span class="k">if</span> <span class="s1">&#39;DATABASE_URL&#39;</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">:</span></span></span>
<span class="line" id="e764cb1L4"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L4"></a><span class="line-content">    <span class="kn">import</span><span class="w"> </span><span class="nn">urllib.parse</span></span></span>
<span class="line" id="e764cb1L5"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L5"></a><span class="line-content">    <span class="n">parsed</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">parse</span><span class="o">.</span><span class="n">urlparse</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s1">&#39;DATABASE_URL&#39;</span><span class="p">])</span></span></span>
<span class="line" id="e764cb1L6"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L6"></a><span class="line-content">    <span class="n">user</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;(.*):(.*)@(.*)&#39;</span><span class="p">,</span> <span class="n">parsed</span><span class="o">.</span><span class="n">netloc</span><span class="p">)</span></span></span>
<span class="line" id="e764cb1L7"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L7"></a><span class="line-content">    <span class="n">db_config</span> <span class="o">=</span> <span class="p">{</span></span></span>
<span class="line" id="e764cb1L8"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L8"></a><span class="line-content">            <span class="s1">&#39;provider&#39;</span><span class="p">:</span> <span class="n">parsed</span><span class="o">.</span><span class="n">scheme</span><span class="p">,</span></span></span>
<span class="line" id="e764cb1L9"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L9"></a><span class="line-content">            <span class="s1">&#39;user&#39;</span><span class="p">:</span> <span class="n">user</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span></span></span>
<span class="line" id="e764cb1L10"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L10"></a><span class="line-content">            <span class="s1">&#39;password&#39;</span><span class="p">:</span> <span class="n">user</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span></span></span>
<span class="line" id="e764cb1L11"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L11"></a><span class="line-content">            <span class="s1">&#39;host&#39;</span><span class="p">:</span> <span class="n">user</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">3</span><span class="p">),</span></span></span>
<span class="line" id="e764cb1L12"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L12"></a><span class="line-content">            <span class="s1">&#39;database&#39;</span><span class="p">:</span> <span class="n">parsed</span><span class="o">.</span><span class="n">path</span><span class="p">[</span><span class="mi">1</span><span class="p">:],</span></span></span>
<span class="line" id="e764cb1L13"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L13"></a><span class="line-content">            <span class="c1"># charset and collation must be specified, as the MySQL defaults do</span></span></span>
<span class="line" id="e764cb1L14"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L14"></a><span class="line-content">            <span class="c1"># not properly support emoji and other 4-byte characters</span></span></span>
<span class="line" id="e764cb1L15"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L15"></a><span class="line-content">            <span class="s1">&#39;charset&#39;</span><span class="p">:</span> <span class="s1">&#39;utf8mb4&#39;</span><span class="p">,</span></span></span>
<span class="line" id="e764cb1L16"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L16"></a><span class="line-content">            <span class="s1">&#39;collation&#39;</span><span class="p">:</span> <span class="s1">&#39;utf8mb4_bin&#39;</span><span class="p">,</span></span></span>
<span class="line" id="e764cb1L17"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L17"></a><span class="line-content">        <span class="p">}</span></span></span>
<span class="line" id="e764cb1L18"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L18"></a><span class="line-content"><span class="k">else</span><span class="p">:</span></span></span>
<span class="line" id="e764cb1L19"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L19"></a><span class="line-content">    <span class="n">db_config</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;provider&#39;</span><span class="p">:</span> <span class="s1">&#39;sqlite&#39;</span><span class="p">,</span> <span class="s1">&#39;filename&#39;</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">APP_PATH</span><span class="p">,</span> <span class="s1">&#39;index.db&#39;</span><span class="p">)}</span></span></span>
<span class="line" id="e764cb1L20"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L20"></a><span class="line-content"></span></span>
<span class="line" id="e764cb1L21"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L21"></a><span class="line-content"><span class="n">config</span> <span class="o">=</span> <span class="p">{</span></span></span>
<span class="line" id="e764cb1L22"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L22"></a><span class="line-content">    <span class="s1">&#39;database_config&#39;</span><span class="p">:</span> <span class="n">db_config</span><span class="p">,</span></span></span>
<span class="line" id="e764cb1L23"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb1L23"></a><span class="line-content">    <span class="c1"># ...</span></span></span>
</pre></figure><p>Then when running the site, set an environment variable such as:</p><figure class="blockcode"><pre><span class="line"><span class="line-content">DATABASE_URL=&#x27;mysql://username:password@server/dbname&#x27;</span></span>
</pre></figure><p>If migrating from SQLite to MySQL, it is a good idea to create the index first before flipping the configuration:</p><figure class="blockcode"><pre><span class="line"><span class="line-content">DATABASE_URL=&#x27;mysql://username:password@server/dbname&#x27; poetry run flask publ reindex</span></span>
</pre></figure><p>An alternate way to store the database configuration is to put it into a local <code>db_config.py</code> file, like so:</p><figure class="blockcode"><figcaption>db_config.py</figcaption><pre class="highlight" data-language="python" data-line-numbers><span class="line" id="e764cb4L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb4L1"></a><span class="line-content"><span class="n">db_config</span> <span class="o">=</span> <span class="p">{</span></span></span>
<span class="line" id="e764cb4L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb4L2"></a><span class="line-content">    <span class="s1">&#39;provider&#39;</span><span class="p">:</span> <span class="s1">&#39;mysql&#39;</span><span class="p">,</span></span></span>
<span class="line" id="e764cb4L3"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb4L3"></a><span class="line-content">    <span class="s1">&#39;user&#39;</span><span class="p">:</span> <span class="s1">&#39;db username&#39;</span><span class="p">,</span></span></span>
<span class="line" id="e764cb4L4"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb4L4"></a><span class="line-content">    <span class="s1">&#39;password&#39;</span><span class="p">:</span> <span class="s1">&#39;db password&#39;</span><span class="p">,</span></span></span>
<span class="line" id="e764cb4L5"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb4L5"></a><span class="line-content">    <span class="s1">&#39;host&#39;</span><span class="p">:</span> <span class="s1">&#39;localhost&#39;</span><span class="p">,</span></span></span>
<span class="line" id="e764cb4L6"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb4L6"></a><span class="line-content">    <span class="s1">&#39;database&#39;</span><span class="p">:</span> <span class="s1">&#39;my_site&#39;</span><span class="p">,</span></span></span>
<span class="line" id="e764cb4L7"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb4L7"></a><span class="line-content">    <span class="s1">&#39;charset&#39;</span><span class="p">:</span> <span class="s1">&#39;utf8mb4&#39;</span><span class="p">,</span></span></span>
<span class="line" id="e764cb4L8"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb4L8"></a><span class="line-content">    <span class="s1">&#39;collation&#39;</span><span class="p">:</span> <span class="s1">&#39;utf8mb4_bin&#39;</span></span></span>
<span class="line" id="e764cb4L9"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb4L9"></a><span class="line-content"><span class="p">}</span></span></span>
</pre></figure><figure class="blockcode"><figcaption>app.py</figcaption><pre class="highlight" data-language="python" data-line-numbers><span class="line" id="e764cb5L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb5L1"></a><span class="line-content"><span class="c1"># ...</span></span></span>
<span class="line" id="e764cb5L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb5L2"></a><span class="line-content"></span></span>
<span class="line" id="e764cb5L3"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb5L3"></a><span class="line-content"><span class="k">try</span><span class="p">:</span></span></span>
<span class="line" id="e764cb5L4"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb5L4"></a><span class="line-content">    <span class="kn">from</span><span class="w"> </span><span class="nn">.db_config</span><span class="w"> </span><span class="kn">import</span> <span class="n">db_config</span></span></span>
<span class="line" id="e764cb5L5"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb5L5"></a><span class="line-content"><span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span></span></span>
<span class="line" id="e764cb5L6"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb5L6"></a><span class="line-content">    <span class="n">db_config</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;provider&#39;</span><span class="p">:</span> <span class="s1">&#39;sqlite&#39;</span><span class="p">,</span> <span class="s1">&#39;filename&#39;</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">APP_PATH</span><span class="p">,</span> <span class="s1">&#39;index.db&#39;</span><span class="p">)}</span></span></span>
<span class="line" id="e764cb5L7"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb5L7"></a><span class="line-content"></span></span>
<span class="line" id="e764cb5L8"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb5L8"></a><span class="line-content"><span class="n">config</span> <span class="o">=</span> <span class="p">{</span></span></span>
<span class="line" id="e764cb5L9"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb5L9"></a><span class="line-content">    <span class="s1">&#39;databse_config&#39;</span><span class="p">:</span> <span class="n">db_config</span><span class="p">,</span></span></span>
<span class="line" id="e764cb5L10"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb5L10"></a><span class="line-content">    <span class="c1"># ...</span></span></span>
<span class="line" id="e764cb5L11"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/764-Using-MySQL-MariaDB-as-your-backing-store#e764cb5L11"></a><span class="line-content"><span class="p">}</span></span></span>
</pre></figure><p>but as always it is important to ensure the security of this file; environment-based configuration is traditionally considered to be much easier to secure and prevent mishaps such as accidentally checking it into source control.</p>

]]>
        </content>
    </entry>
    
    <entry>
        <title>Setting up caching</title>
        <link href="https://publ.beesbuzz.biz/manual/deploying/20-Setting-up-caching" rel="alternate" type="text/html" />
        <published>2020-02-05T23:44:04-08:00</published>
        <updated>2020-02-05T23:44:04-08:00</updated>
        <id>urn:uuid:a76ad2de-07c7-53d3-84a0-70835dc90087</id>
        <author><name>fluffy</name></author>
        <content type="html">
<![CDATA[
<p>Some pointers for setting up the page caching mechanism</p>

<p>When templates start to get particularly complex, Publ can start to slow down; this is one of the tradeoffs when using a dynamic site generator, rather than a static one. Fortunately, it is fairly straightforward to configure Publ with caching; here are some pointers on how.</p><h2 id="20_h2_1_Basics"><a href="https://publ.beesbuzz.biz/manual/deploying/20-Setting-up-caching#20_h2_1_Basics"></a>Basics</h2><p>Entire textbooks can (and have been) written on caching and their optimum usage. This is not intended to be an entire textbook, but rather a set of brief-ish guidelines for how to configure Publ&rsquo;s caching mechanism.</p><h3 id="20_h3_2_What-is-a-cache"><a href="https://publ.beesbuzz.biz/manual/deploying/20-Setting-up-caching#20_h3_2_What-is-a-cache"></a>What is a cache?</h3><p>At its most basic and general, a cache is a temporary storage area where intermediate results get stored for a while.</p><p>Fundamentally, there are two algorithms involved in a cache: key generation, and result generation.</p><p>The key is basically a filename that tells the cache where to look for a result, and this is computed based on the unique aspects that are involved in generating the result. In the case of Publ&rsquo;s page cache, the key is based on what&rsquo;s being looked at (the selected category, template, entry, and URL parameters), how it&rsquo;s being looked at (the URL), and who&rsquo;s looking at it (the current user, if any).</p><p>The result is the result of performing the operation that&rsquo;s being cached. In this case, this is the rendered content of the template.</p><p>The goal in any cache is to correctly produce the right result while reusing those results as much as possible, while taking less time on average than what it would take to simply compute the result each time.</p><h3 id="20_h3_3_Performance-tradeoffs"><a href="https://publ.beesbuzz.biz/manual/deploying/20-Setting-up-caching#20_h3_3_Performance-tradeoffs"></a>Performance tradeoffs</h3><p>When setting up a cache, you need to consider what the right balance is between memory usage, performance, and immediacy. These three things are at odds with one another and there is fundamentally no perfect solution that maximizes all three.</p><p>Generally-speaking there are two statistics we are looking for in trying to optimize a cache:</p>
<ul>
<li><strong>Hit rate</strong>: How often a page render can be reused; we want this to be as high as possible</li>
<li><strong>Staleness</strong>: How out-of-date a page render can be; we want this to be as low as tolerable</li>
</ul>
<p>There is a third statistic which also matters, namely the active cache size (also called the &ldquo;hot size,&rdquo; among other things) &ndash; this is simply the total amount of storage used by page renders.</p><p>To achieve these goals, there are two &ldquo;knobs&rdquo; of particular interest: maximum cache size, and expiration time.</p><p>Increasing the expiration time will increase the hit rate, while also increasing the staleness. To understand why, if a page is only accessed once every 15 minutes, and the expiration time is only 5 minutes, then the cached result will be expired before the page is accessed again, making the cache useless. But, if the expiration time is one hour, then if a page changes at all, the update won&rsquo;t appear until an hour after it was rendered.</p><p>The other knob, maximum cache size, is simply a measure of how much can be kept in the cache. As long as the expiration time is finite, the cache will never grow to be infinitely large, but you might still want to put a limit on how large it can grow. Raising the cache size won&rsquo;t necessarily increase the hit rate, but decreasing the cache size to be less than the active cache size will decrease it.<sup id="r_e20_fn1"><a href="https://publ.beesbuzz.biz/manual/deploying/20-Setting-up-caching#d_e20_fn1" rel="footnote">1</a></sup></p><h3 id="20_h3_4_A-note-on-staleness"><a href="https://publ.beesbuzz.biz/manual/deploying/20-Setting-up-caching#20_h3_4_A-note-on-staleness"></a><span id="expiration">A note on staleness</span></h3><p>To mitigate the staleness problem, Publ uses aspects of when content was last edited as part of its caching mechanism, so if content changes that might affect a page, all previous versions of that page will be discarded.<sup id="r_e20_fn2"><a href="https://publ.beesbuzz.biz/manual/deploying/20-Setting-up-caching#d_e20_fn2" rel="footnote">2</a></sup> So, while many caching systems recommend only setting the expiration time to the maximum amount of time you can tolerate a change not being available, Publ does not have this issue.</p><p>However, some things that Publ can do will still become stale. For example, things that are essentially non-deterministic (such as things based on random numbers) or based on the current time (such as <code>entry.date.humanize()</code>) will still be subject to becoming stale. So if you use any of these things in your templates, you&rsquo;ll want to set your expiration time accordingly. Some guidelines:</p>
<ul>
<li>If you use <code>entry.date.humanize()</code>, an expiration time of around 1 hour is probably fine (although this will make a recent entry&rsquo;s relative time appear to be wrong for its first hour of existence or so)</li>
<li>If you use random number generation for whatever reason (such as displaying a random image on a particular page), the expiration time should be for however long you are willing to tolerate the number staying the same</li>
<li>If you want to display the current time on the page for some reason<sup id="r_e20_fn3"><a href="https://publ.beesbuzz.biz/manual/deploying/20-Setting-up-caching#d_e20_fn3" rel="footnote">3</a></sup>, the expiration time should be for the most &ldquo;slow&rdquo; you&rsquo;re willing to have the clock be.</li>
</ul>
<p>Also, if you plan on using any sort of monitoring service (munin, Pingdom, etc.) to measure page load time over time (to get an ongoing performance indicator), it&rsquo;s a good idea to set your expiration time to a nearby prime number; for example, if you want your expiration time to be around an hour, try values of 3593 or 3659 or the like. This helps to prevent sampling bias and gives a much better overall average.</p><h2 id="20_h2_5_Configuration"><a href="https://publ.beesbuzz.biz/manual/deploying/20-Setting-up-caching#20_h2_5_Configuration"></a>Configuration</h2><p>Publ uses <a href="https://flask-caching.readthedocs.io/en/latest/">flask-caching</a> for its caching layer. The short version of its documentation is it provides caching backends for a number of common caching servers (Redis and a few variants of MemcacheD), as well as file-based and in-process caching.</p><p>If you have Redis or MemcacheD available, definitely use those; they have the advantage of persisting beyond your application&rsquo;s run time, and going into a common shared memory pool for all sites that use them, which can be way more memory-efficient than the in-process cache. They also both support distributed caches.</p><p>If you are self-hosting and trying to decide which cache server to go with, I suggest MemcacheD, as it&rsquo;s by far the easiest to install and configure, and most distributions pre-configure it with sensible defaults.</p><p>If you don&rsquo;t have any of those (for example, you&rsquo;re on shared hosting that doesn&rsquo;t allow you to run your own services), your best choices<sup id="r_e20_fn4"><a href="https://publ.beesbuzz.biz/manual/deploying/20-Setting-up-caching#d_e20_fn4" rel="footnote">4</a></sup> are <code>FileSystemCache</code> (file-based) and <code>SimpleCache</code> (in-process), which each have strengths and weaknesses. Both of them suffer from not being configurable based on actual storage size; they can only track the number of items in the hot cache. <code>SimpleCache</code> is faster, but also makes your process take more memory &ndash; a big concern if you&rsquo;re on a shared system where memory usage is limited. <code>FileSystemCache</code> is generally friendlier and fast <em>enough</em> (and also will take advantage of the operating system&rsquo;s file cache which makes it kinda-sorta similar to using a caching server), but its performance disadvantage can end up slowing the site down in many cases. But if you can look at the state of the filesystem, <code>FileSystemCache</code> gives you better visibility into what&rsquo;s happening with the cache, which can give you better ideas for how to tune it.</p><p>In general, I&rsquo;d recommend this priority order:</p>
<ol>
<li>MemcacheD or Redis</li>
<li>FileSystemCache (if you have lots of storage available)</li>
<li>SimpleCache (if you have lots of RAM available)</li>
</ol>
<p>Regardless of caching backend, in your application&rsquo;s <a href="https://publ.beesbuzz.biz/manual/865-Python-API#cache">cache configuration</a> you should configure the following:</p>
<ul>
<li><code>CACHE_KEY_PREFIX</code>: Set this to some random but fixed string (this helps to prevent certain kinds of attacks that are possible if you share the cache with someone else)</li>
<li><code>CACHE_DEFAULT_TIMEOUT</code>: Set this to your expiration time, as discussed <a href="https://publ.beesbuzz.biz/manual/deploying/feed#expiration">above</a></li>
</ul>
<p>Some backend-specific notes are below.</p><h3 id="20_h3_6_MemcacheD"><a href="https://publ.beesbuzz.biz/manual/deploying/20-Setting-up-caching#20_h3_6_MemcacheD"></a>MemcacheD</h3><p>In order to use MemcacheD you&rsquo;ll also need to add a MemcacheD client to your Python environment. I generally use <code>python-memcached</code> as it&rsquo;s easier to install (especially in cross-platform scenarios), but <code>libmc</code> and <code>pylibmc</code> both have some advantages in performance-critical and large-scale scenarios, being slightly faster as well as supporting <a href="https://en.wikipedia.org/wiki/Consistent_hashing">consistent hashing</a>.</p><p>If you&rsquo;re on Google AppEngine, a suitable client is already provided to you and there is no reason to add your own.</p><h3 id="20_h3_7_SimpleCache"><a href="https://publ.beesbuzz.biz/manual/deploying/20-Setting-up-caching#20_h3_7_SimpleCache"></a>SimpleCache</h3><p>Set the value of <code>CACHE_THRESHOLD</code> to limit the number of items that can be kept in the cache. As noted above, there is no way to limit the size directly, so if you have a specific allocation limit in mind, try to figure out what the average size of a page is (in bytes), and divide your allocation limit by that. That is the value you should use.</p><h3 id="20_h3_8_FileSystemCache"><a href="https://publ.beesbuzz.biz/manual/deploying/20-Setting-up-caching#20_h3_8_FileSystemCache"></a>FileSystemCache</h3><p>Similarly to SimpleCache, this uses <code>CACHE_THRESHOLD</code> to limit the number of items in the cache, rather than the total storage size. Since filesystem space is usually much more plentiful than RAM, there&rsquo;s no reason to be particularly miserly with this. Unless you start to run out of storage space, anyway</p><p>You should also make sure that the <code>CACHE_DIR</code> is set to a directory that you have write access to, and you should set <code>CACHE_OPTIONS</code> to <code>{&#39;mode&#39;: 0o600}</code> (the default).</p>

]]>
        </content>
    </entry>
    
    <entry>
        <title>Hosting options</title>
        <link href="https://publ.beesbuzz.biz/manual/deploying/545-Hosting-options" rel="alternate" type="text/html" />
        <published>2019-10-12T11:01:01-07:00</published>
        <updated>2019-10-12T11:01:01-07:00</updated>
        <id>urn:uuid:8d9bf039-ad27-5772-a5fc-aaf9b869c19c</id>
        <author><name>fluffy</name></author>
        <content type="html">
<![CDATA[
<p>Here&rsquo;s some options when it comes to hosting Publ sites, with pluses and minuses.</p>

<p>If you know of something that isn&rsquo;t listed, please <a href="https://publ.beesbuzz.biz/newissue">open an issue</a>. Note that a listing for a specific provider is not necessarily an endorsement.</p><h2 id="545_h2_1_Shared-hosting"><a href="https://publ.beesbuzz.biz/manual/deploying/545-Hosting-options#545_h2_1_Shared-hosting"></a>Shared hosting</h2><p>If you can find a compatible shared hosting setup, this is by far the easiest and least-costly way to get running.</p><p>Shared hosting providers typically offer very inexpensive bandwidth and storage, with a tradeoff of not having as much flexibility with your environment and service stack. In addition, you&rsquo;ll be sharing resources with other users, which can have both performance and security implications.</p><p>Additionally, shared hosting providers typically limit you to PHP and/or CGI. However, there are a few known shared hosting providers which do support Flask (and therefore Publ) to some extent:</p>
<ul>
<li><a href="https://nearlyfreespeech.net/">Nearly Free Speech</a> claims <a href="https://www.nearlyfreespeech.net/about/faq#WorkingApps">direct support for Flask</a></li>
<li><del><a href="https://dreamhost.com/">Dreamhost</a> ostensibly supports Flask via their <a href="https://help.dreamhost.com/hc/en-us/articles/215769548-Passenger-and-Python-WSGI">Passenger WSGI wrapper</a> (although I&rsquo;ve had <a href="https://publ.beesbuzz.biz/blog/358-So-much-for-Dreamhost">issues with them in the past</a>)</del> This is no longer the case.</li>
</ul>
<p>When considering a shared hosting provider, look specifically to see if they support Flask, or a bit more broadly, WSGI. If they support Django (which is another common WSGI-based framework) it is very likely to support Flask.</p><p>However, &ldquo;supporting Python&rdquo; doesn&rsquo;t necessarily mean supporting Python WSGI, as sometimes it just means being able to run Python CGI (which is a different, older mechanism which is unsuitable for a modern web stack). If in doubt, ask their support folks if they support Flask.</p><p>Once you do find a host, refer to their guides for setting up Flask or WSGI applications to get started with running Publ.</p><h2 id="545_h2_2_Self-hosting"><a href="https://publ.beesbuzz.biz/manual/deploying/545-Hosting-options#545_h2_2_Self-hosting"></a>Self-hosting</h2><p>If you&rsquo;re savvy with running a Linux server, this is a pretty good choice. The advantages are having complete control over your hosting setup and generally having the cheapest storage available, and a lower overall cost per site if you run multiple sites. The main disadvantage is having to be your own sysadmin, which can be a pretty big burden.</p><p>On all of these choices, you&rsquo;d be running a fronting web server (usually nginx or Apache) and doing a reverse proxy to your Flask application; see the <a href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ">self-hosting guide</a> for more detailed information.</p><h3 id="545_h3_3_VPS-providers"><a href="https://publ.beesbuzz.biz/manual/deploying/545-Hosting-options#545_h3_3_VPS-providers"></a>VPS providers</h3><p>A virtual private server gives you complete control over a virtual slice of hardware. Typically this provides better fault tolerance, easier migration, and simpler server management, with the downside of being slightly lower in performance (in ways which don&rsquo;t matter for hosting websites most of the time).</p><p>Some known providers:</p>
<ul>
<li><a href="https://www.linode.com/?r=3387618616c77ee52a3a617c0218697a9c36bc9b">Linode</a></li>
<li><a href="https://www.digitalocean.com/">Digital Ocean</a></li>
<li><a href="https://aws.amazon.com">Amazon EC2</a></li>
</ul>
<h3 id="545_h3_4_Physical-hosting"><a href="https://publ.beesbuzz.biz/manual/deploying/545-Hosting-options#545_h3_4_Physical-hosting"></a>Physical hosting</h3><p>Colocation, either with managed hardware or with bring-your-own device. Not for the faint of heart. Generally gives you more performance but worse bang for your buck, worse fault-tolerance, and much more of a management headache when things go wrong.</p><p>For some people this can even mean running a server on your home Internet connection. Many ISPs do not take kindly to this; check your terms of service before doing this.</p><h2 id="545_h2_5_Cloud-app-hosting"><a href="https://publ.beesbuzz.biz/manual/deploying/545-Hosting-options#545_h2_5_Cloud-app-hosting"></a>Cloud app hosting</h2><p>Cloud app hosting means you provide an image for an application which gets run only when it&rsquo;s actively being used.</p><p>The advantages are that there&rsquo;s a lot less administrative overhead on your end, and it&rsquo;s usually easier to deploy your site and also handle scaling and so on.</p><p>The disadvantages are numerous, however; usually there&rsquo;s a much lower limit on how much content you can host within the container (and Publ is not designed to use content kept in an external object store), deployments can be significantly slower, and when the site &ldquo;sleeps&rdquo; it can take quite some time for it to serve the first page while it wakes up. Also, storage, CPU, and bandwidth tend to be much more expensive than dedicated hosting.</p><p>Some known providers:</p>
<ul>
<li><a href="https://heroku.com/">Heroku</a></li>
<li><a href="https://console.cloud.google.com/appengine">Google App Engine</a></li>
</ul>


]]>
        </content>
    </entry>
    
    <entry>
        <title>Continuous deployment with git</title>
        <link href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git" rel="alternate" type="text/html" />
        <published>2018-12-16T23:23:07-08:00</published>
        <updated>2018-12-16T23:23:07-08:00</updated>
        <id>urn:uuid:b023c99e-0f41-51ea-9d41-5e575b37339d</id>
        <author><name>fluffy</name></author>
        <content type="html">
<![CDATA[
<p>How to use git hooks to automatically deploy site content</p>

<p>It&rsquo;s pretty common to use git to host your website files. There are a few different ways that you can use git itself to automate the deployment of site updates, depending on the specifics of your git hosting situation. The below methods should cover the vast majority of git-based workflows, at least if you&rsquo;re <a href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ">self-hosting Publ</a>.</p><h2 id="441_h2_1_Deployment-script"><a href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#441_h2_1_Deployment-script"></a>Deployment script</h2><p>Regardless of your actual git hosting situation, you will need a deployment script, which does a <code>git pull</code> and performs different tasks depending on what&rsquo;s been updated. Save this file as <code>deploy.sh</code> in your website repository, and make sure it&rsquo;s set executable:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e441cb1L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L1"></a><span class="line-content"><span class="ch">#!/bin/sh</span></span></span>
<span class="line" id="e441cb1L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L2"></a><span class="line-content"><span class="c1"># wrapper script to pull the latest site content and redeploy</span></span></span>
<span class="line" id="e441cb1L3"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L3"></a><span class="line-content"></span></span>
<span class="line" id="e441cb1L4"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L4"></a><span class="line-content"><span class="nb">cd</span><span class="w">  </span><span class="k">$(</span>dirname<span class="w"> </span><span class="nv">$0</span><span class="k">)</span></span></span>
<span class="line" id="e441cb1L5"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L5"></a><span class="line-content"></span></span>
<span class="line" id="e441cb1L6"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L6"></a><span class="line-content"><span class="c1"># see where in the history we are now</span></span></span>
<span class="line" id="e441cb1L7"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L7"></a><span class="line-content"><span class="nv">PREV</span><span class="o">=</span><span class="k">$(</span>git<span class="w"> </span>rev-parse<span class="w"> </span>--short<span class="w"> </span>HEAD<span class="k">)</span></span></span>
<span class="line" id="e441cb1L8"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L8"></a><span class="line-content"></span></span>
<span class="line" id="e441cb1L9"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L9"></a><span class="line-content">git<span class="w"> </span>pull<span class="w"> </span>--ff-only<span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="nb">exit</span><span class="w"> </span><span class="m">1</span></span></span>
<span class="line" id="e441cb1L10"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L10"></a><span class="line-content"></span></span>
<span class="line" id="e441cb1L11"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L11"></a><span class="line-content"><span class="k">if</span><span class="w"> </span>git<span class="w"> </span>diff<span class="w"> </span>--name-only<span class="w"> </span><span class="nv">$PREV</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>-qE<span class="w"> </span><span class="s1">&#39;^(templates/|app\.py|users\.cfg)&#39;</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="k">then</span></span></span>
<span class="line" id="e441cb1L12"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L12"></a><span class="line-content"><span class="w">    </span><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;Configuration or template change detected&quot;</span></span></span>
<span class="line" id="e441cb1L13"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L13"></a><span class="line-content"><span class="w">    </span><span class="nv">disposition</span><span class="o">=</span>reload-or-restart</span></span>
<span class="line" id="e441cb1L14"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L14"></a><span class="line-content"><span class="k">fi</span></span></span>
<span class="line" id="e441cb1L15"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L15"></a><span class="line-content"></span></span>
<span class="line" id="e441cb1L16"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L16"></a><span class="line-content"><span class="k">if</span><span class="w"> </span>git<span class="w"> </span>diff<span class="w"> </span>--name-only<span class="w"> </span><span class="nv">$PREV</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>-q<span class="w"> </span>poetry.lock<span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="k">then</span></span></span>
<span class="line" id="e441cb1L17"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L17"></a><span class="line-content"><span class="w">    </span><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;poetry.lock changed&quot;</span></span></span>
<span class="line" id="e441cb1L18"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L18"></a><span class="line-content"><span class="w">    </span>poetry<span class="w"> </span>install<span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="nb">exit</span><span class="w"> </span><span class="m">1</span></span></span>
<span class="line" id="e441cb1L19"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L19"></a><span class="line-content"><span class="w">    </span><span class="nv">disposition</span><span class="o">=</span>restart</span></span>
<span class="line" id="e441cb1L20"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L20"></a><span class="line-content"><span class="k">fi</span></span></span>
<span class="line" id="e441cb1L21"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L21"></a><span class="line-content"></span></span>
<span class="line" id="e441cb1L22"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L22"></a><span class="line-content"><span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="s2">&quot;</span><span class="nv">$1</span><span class="s2">&quot;</span><span class="w"> </span>!<span class="o">=</span><span class="w"> </span><span class="s2">&quot;nokill&quot;</span><span class="w"> </span><span class="o">]</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>!<span class="w"> </span>-z<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$disposition</span><span class="s2">&quot;</span><span class="w"> </span><span class="o">]</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="k">then</span></span></span>
<span class="line" id="e441cb1L23"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L23"></a><span class="line-content"><span class="w">    </span><span class="c1"># insert server restart command here (see note), e.g.</span></span></span>
<span class="line" id="e441cb1L24"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L24"></a><span class="line-content"><span class="w">    </span><span class="c1"># systemctl --user $disposition SERVICE-NAME.service</span></span></span>
<span class="line" id="e441cb1L25"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb1L25"></a><span class="line-content"><span class="k">fi</span></span></span>
</pre></figure><p>The remainder of the deployment process depends on how you&rsquo;re actually hosting your git repository.</p><h2 id="441_h2_2_Self-hosted-git-repository"><a href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#441_h2_2_Self-hosted-git-repository"></a>Self-hosted git repository</h2><h3 id="441_h3_3_Repository-on-same-server-as-the"><a href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#441_h3_3_Repository-on-same-server-as-the"></a>Repository on same server as the website</h3><p>For this example, we will keep the main git repository in <code>$HOME/sitefiles/example.com.git</code> and the deployment directory in <code>$HOME/example.com</code>.</p><p>On your webserver, create a private bare git repository wherever you want it; for example, on the server, run:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e441cb2L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L1"></a><span class="line-content"><span class="c1"># change this!</span></span></span>
<span class="line" id="e441cb2L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L2"></a><span class="line-content"><span class="nv">SITENAME</span><span class="o">=</span>example.com</span></span>
<span class="line" id="e441cb2L3"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L3"></a><span class="line-content"></span></span>
<span class="line" id="e441cb2L4"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L4"></a><span class="line-content"><span class="c1"># create the bare repository</span></span></span>
<span class="line" id="e441cb2L5"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L5"></a><span class="line-content">mkdir<span class="w"> </span>-p<span class="w"> </span><span class="nv">$HOME</span>/sitefiles</span></span>
<span class="line" id="e441cb2L6"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L6"></a><span class="line-content">git<span class="w"> </span>init<span class="w"> </span>--bare<span class="w"> </span><span class="nv">$HOME</span>/sitefiles/<span class="nv">$SITENAME</span>.git</span></span>
<span class="line" id="e441cb2L7"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L7"></a><span class="line-content"></span></span>
<span class="line" id="e441cb2L8"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L8"></a><span class="line-content"><span class="c1"># add the post-update hook</span></span></span>
<span class="line" id="e441cb2L9"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L9"></a><span class="line-content">cat<span class="w"> </span>&gt;<span class="w"> </span><span class="nv">$HOME</span>/sitefiles/<span class="nv">$SITENAME</span>.git/hooks/post-update<span class="w"> </span><span class="s">&lt;&lt; EOF</span></span></span>
<span class="line" id="e441cb2L10"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L10"></a><span class="line-content"><span class="s">#!/bin/sh</span></span></span>
<span class="line" id="e441cb2L11"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L11"></a><span class="line-content"></span></span>
<span class="line" id="e441cb2L12"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L12"></a><span class="line-content"><span class="s">echo &quot;Deploying new site content...&quot;</span></span></span>
<span class="line" id="e441cb2L13"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L13"></a><span class="line-content"></span></span>
<span class="line" id="e441cb2L14"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L14"></a><span class="line-content"><span class="s">cd \$HOME/$SITENAME</span></span></span>
<span class="line" id="e441cb2L15"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L15"></a><span class="line-content"><span class="s">unset GIT_DIR</span></span></span>
<span class="line" id="e441cb2L16"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L16"></a><span class="line-content"><span class="s">if [ ! -x ./deploy.sh ] ; then</span></span></span>
<span class="line" id="e441cb2L17"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L17"></a><span class="line-content"><span class="s">    echo &quot;Deployment script not available or not executable&quot; 1&gt;&amp;2</span></span></span>
<span class="line" id="e441cb2L18"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L18"></a><span class="line-content"><span class="s">    exit 1</span></span></span>
<span class="line" id="e441cb2L19"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L19"></a><span class="line-content"><span class="s">fi</span></span></span>
<span class="line" id="e441cb2L20"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L20"></a><span class="line-content"><span class="s">./deploy.sh || echo &quot;Deployment script failed&quot;</span></span></span>
<span class="line" id="e441cb2L21"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L21"></a><span class="line-content"><span class="s">EOF</span></span></span>
<span class="line" id="e441cb2L22"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L22"></a><span class="line-content">chmod<span class="w"> </span>u+x<span class="w"> </span><span class="nv">$HOME</span>/sitefiles/<span class="nv">$SITENAME</span>.git/hooks/post-update</span></span>
<span class="line" id="e441cb2L23"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L23"></a><span class="line-content"></span></span>
<span class="line" id="e441cb2L24"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L24"></a><span class="line-content"><span class="c1"># set up the live/deployment workspace</span></span></span>
<span class="line" id="e441cb2L25"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L25"></a><span class="line-content"><span class="nb">cd</span><span class="w"> </span><span class="nv">$HOME</span></span></span>
<span class="line" id="e441cb2L26"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L26"></a><span class="line-content">git<span class="w"> </span>clone<span class="w"> </span><span class="nv">$HOME</span>/sitefiles/<span class="nv">$SITENAME</span>.git</span></span>
<span class="line" id="e441cb2L27"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L27"></a><span class="line-content"><span class="c1"># optional: make this repository share the raw objects (to save some disk space)</span></span></span>
<span class="line" id="e441cb2L28"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L28"></a><span class="line-content"><span class="c1"># see https://git.wiki.kernel.org/index.php/Git_FAQ#How_to_share_objects_between_existing_repositories.3F</span></span></span>
<span class="line" id="e441cb2L29"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L29"></a><span class="line-content"><span class="nb">cd</span><span class="w"> </span><span class="nv">$SITENAME</span></span></span>
<span class="line" id="e441cb2L30"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L30"></a><span class="line-content"><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;</span><span class="nv">$HOME</span><span class="s2">/sitefiles/</span><span class="nv">$SITENAME</span><span class="s2">.git/objects/&quot;</span><span class="w"> </span>&gt;<span class="w"> </span>.git/objects/info/alternates</span></span>
<span class="line" id="e441cb2L31"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb2L31"></a><span class="line-content">git<span class="w"> </span>gc</span></span>
</pre></figure><p>Now you&rsquo;ll have a bare repository in <code>$HOME/sitefiles/example.com.git</code> and a live deployment workspace in <code>$HOME/example.com</code>, and pushing to the bare repository will run the deployment script in the live workspace, if it exists.</p><p>On your local repository (i.e. where you&rsquo;re actually working on your site) add the bare repository as your remote:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e441cb3L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb3L1"></a><span class="line-content">git<span class="w"> </span>remote<span class="w"> </span>add<span class="w"> </span>origin<span class="w"> </span>user@server.example.com:sitefiles/example.com.git</span></span>
<span class="line" id="e441cb3L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb3L2"></a><span class="line-content">git<span class="w"> </span>push<span class="w"> </span>-u<span class="w"> </span>origin<span class="w"> </span>master</span></span>
</pre></figure><p>This should push all of your content into the bare repository; however, since the live workspace won&rsquo;t yet have <code>deploy.sh</code> you&rsquo;ll need to do one <code>git pull</code> manually. After this, every push to the bare repository should automatically run your deployment script.</p><h3 id="441_h3_4_Separate-servers-using-an-ssh-ke"><a href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#441_h3_4_Separate-servers-using-an-ssh-ke"></a>Separate servers using an <code>ssh</code> key</h3><p>If you keep your git repository on a separate server from where it&rsquo;s deployed to, set up an <a href="https://www.ssh.com/ssh/key/">ssh key</a> or other authentication mechanism other than password so that you can do passwordless ssh from the repository server to the deployment server, and then add this as a <code>post-update</code> hook on the repository:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e441cb4L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb4L1"></a><span class="line-content"><span class="ch">#!/bin/sh</span></span></span>
<span class="line" id="e441cb4L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb4L2"></a><span class="line-content"></span></span>
<span class="line" id="e441cb4L3"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb4L3"></a><span class="line-content"><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;Deploying new site content...&quot;</span></span></span>
<span class="line" id="e441cb4L4"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb4L4"></a><span class="line-content"></span></span>
<span class="line" id="e441cb4L5"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb4L5"></a><span class="line-content">ssh<span class="w"> </span>DEPLOYMENT_SERVER<span class="w"> </span><span class="s1">&#39;cd example.com &amp;&amp; ./deploy.sh&#39;</span></span></span>
</pre></figure><p>replacing <code>DEPLOYMENT_SERVER</code> with the actual server name, and <code>example.com</code> with the directory that contains the site deployment.</p><h2 id="441_h2_5_Simple-webhook-deployment"><a href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#441_h2_5_Simple-webhook-deployment"></a>Simple webhook deployment</h2><p>If you don&rsquo;t have the ability to run arbitrary <code>post-update</code> hooks but do have some sort of webhook functionality, you can add a webhook to your Publ site to run <code>deploy.sh</code>; for example, you can add this to your <code>app.py</code>:</p><figure class="blockcode"><pre class="highlight" data-language="python" data-line-numbers><span class="line" id="e441cb5L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L1"></a><span class="line-content"><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s1">&#39;/_deploy&#39;</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;POST&#39;</span><span class="p">])</span></span></span>
<span class="line" id="e441cb5L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L2"></a><span class="line-content"><span class="k">def</span><span class="w"> </span><span class="nf">deploy</span><span class="p">():</span></span></span>
<span class="line" id="e441cb5L3"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L3"></a><span class="line-content">    <span class="kn">import</span><span class="w"> </span><span class="nn">threading</span></span></span>
<span class="line" id="e441cb5L4"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L4"></a><span class="line-content">    <span class="kn">import</span><span class="w"> </span><span class="nn">signal</span></span></span>
<span class="line" id="e441cb5L5"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L5"></a><span class="line-content">    <span class="kn">import</span><span class="w"> </span><span class="nn">subprocess</span></span></span>
<span class="line" id="e441cb5L6"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L6"></a><span class="line-content">    <span class="kn">import</span><span class="w"> </span><span class="nn">flask</span></span></span>
<span class="line" id="e441cb5L7"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L7"></a><span class="line-content"></span></span>
<span class="line" id="e441cb5L8"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L8"></a><span class="line-content">    <span class="k">if</span> <span class="n">flask</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;secret&#39;</span><span class="p">)</span> <span class="o">!=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;REDEPLOY_SECRET&#39;</span><span class="p">):</span></span></span>
<span class="line" id="e441cb5L9"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L9"></a><span class="line-content">        <span class="k">return</span> <span class="n">flask</span><span class="o">.</span><span class="n">abort</span><span class="p">(</span><span class="mi">403</span><span class="p">)</span></span></span>
<span class="line" id="e441cb5L10"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L10"></a><span class="line-content"></span></span>
<span class="line" id="e441cb5L11"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L11"></a><span class="line-content">    <span class="k">try</span><span class="p">:</span></span></span>
<span class="line" id="e441cb5L12"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L12"></a><span class="line-content">        <span class="n">result</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">check_output</span><span class="p">(</span></span></span>
<span class="line" id="e441cb5L13"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L13"></a><span class="line-content">            <span class="p">[</span><span class="s1">&#39;./deploy.sh&#39;</span><span class="p">,</span> <span class="s1">&#39;nokill&#39;</span><span class="p">],</span></span></span>
<span class="line" id="e441cb5L14"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L14"></a><span class="line-content">            <span class="n">stderr</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">STDOUT</span><span class="p">)</span></span></span>
<span class="line" id="e441cb5L15"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L15"></a><span class="line-content">    <span class="k">except</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">CalledProcessError</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span></span></span>
<span class="line" id="e441cb5L16"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L16"></a><span class="line-content">        <span class="n">logging</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">&quot;Deployment failed: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">err</span><span class="o">.</span><span class="n">output</span><span class="p">)</span></span></span>
<span class="line" id="e441cb5L17"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L17"></a><span class="line-content">        <span class="k">return</span> <span class="n">flask</span><span class="o">.</span><span class="n">Response</span><span class="p">(</span><span class="n">err</span><span class="o">.</span><span class="n">output</span><span class="p">,</span> <span class="n">status_code</span><span class="o">=</span><span class="mi">500</span><span class="p">,</span> <span class="n">mimetype</span><span class="o">=</span><span class="s1">&#39;text/plain&#39;</span><span class="p">)</span></span></span>
<span class="line" id="e441cb5L18"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L18"></a><span class="line-content"></span></span>
<span class="line" id="e441cb5L19"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L19"></a><span class="line-content">    <span class="k">def</span><span class="w"> </span><span class="nf">restart_server</span><span class="p">(</span><span class="n">pid</span><span class="p">):</span></span></span>
<span class="line" id="e441cb5L20"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L20"></a><span class="line-content">        <span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;Restarting&quot;</span><span class="p">)</span></span></span>
<span class="line" id="e441cb5L21"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L21"></a><span class="line-content">        <span class="n">os</span><span class="o">.</span><span class="n">kill</span><span class="p">(</span><span class="n">pid</span><span class="p">,</span> <span class="n">signal</span><span class="o">.</span><span class="n">SIGHUP</span><span class="p">)</span></span></span>
<span class="line" id="e441cb5L22"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L22"></a><span class="line-content"></span></span>
<span class="line" id="e441cb5L23"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L23"></a><span class="line-content">    <span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;Restarting server in 3 seconds...&quot;</span><span class="p">)</span></span></span>
<span class="line" id="e441cb5L24"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L24"></a><span class="line-content">    <span class="n">threading</span><span class="o">.</span><span class="n">Timer</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">restart_server</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">[</span><span class="n">os</span><span class="o">.</span><span class="n">getpid</span><span class="p">()])</span><span class="o">.</span><span class="n">start</span><span class="p">()</span></span></span>
<span class="line" id="e441cb5L25"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L25"></a><span class="line-content"></span></span>
<span class="line" id="e441cb5L26"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb5L26"></a><span class="line-content">    <span class="k">return</span> <span class="n">flask</span><span class="o">.</span><span class="n">Response</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">mimetype</span><span class="o">=</span><span class="s1">&#39;text/plain&#39;</span><span class="p">)</span></span></span>
</pre></figure><p>Then, in whatever mechanism you use to run the website, set the environment variable <code>REDEPLOY_SECRET</code> to some secret string. For example, if you&rsquo;re using a <code>systemd</code> service, add a line like:</p><figure class="blockcode"><pre><span class="line"><span class="line-content">Environment=&quot;REDEPLOY_SECRET=the secret password&quot;</span></span>
</pre></figure><p>Deploy these changes to your website and restart it. Now you can configure a webhook on your git repository that sends a POST request to the <code>/_deploy</code> route with the <code>secret</code> parameter set to your <code>REDEPLOY_SECRET</code> key.</p><h2 id="441_h2_6_GitHub-style-web-hooks"><a href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#441_h2_6_GitHub-style-web-hooks"></a>GitHub-style web hooks</h2><p>If you&rsquo;re using GitHub (or something GitHub-compatible) to host your site files, there is a more secure way to run a webhook.</p><p>First, install the <a href="https://pypi.org/project/flask-github-webhook">flask-github-webhook</a> package into your environment (with e.g. <code>poetry add flask-github-webhook</code>).</p><p>Next, add the following to your <code>app.py</code> somewhere after the <code>app</code> object gets created:</p><figure class="blockcode"><pre class="highlight" data-language="python" data-line-numbers><span class="line" id="e441cb7L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L1"></a><span class="line-content"><span class="kn">from</span><span class="w"> </span><span class="nn">flask_github_webhook</span><span class="w"> </span><span class="kn">import</span> <span class="n">GithubWebhook</span></span></span>
<span class="line" id="e441cb7L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L2"></a><span class="line-content"></span></span>
<span class="line" id="e441cb7L3"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L3"></a><span class="line-content"><span class="c1"># Configure the GitHub publishing webhook</span></span></span>
<span class="line" id="e441cb7L4"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L4"></a><span class="line-content"><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">&#39;GITHUB_WEBHOOK_ENDPOINT&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;/_gh&#39;</span></span></span>
<span class="line" id="e441cb7L5"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L5"></a><span class="line-content"><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s1">&#39;GITHUB_WEBHOOK_SECRET&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;GITHUB_SECRET&#39;</span><span class="p">)</span></span></span>
<span class="line" id="e441cb7L6"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L6"></a><span class="line-content"></span></span>
<span class="line" id="e441cb7L7"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L7"></a><span class="line-content"><span class="c1"># Deployment hook for self-hosted instance</span></span></span>
<span class="line" id="e441cb7L8"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L8"></a><span class="line-content"><span class="n">hooks</span> <span class="o">=</span> <span class="n">GithubWebhook</span><span class="p">(</span><span class="n">app</span><span class="p">)</span></span></span>
<span class="line" id="e441cb7L9"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L9"></a><span class="line-content"></span></span>
<span class="line" id="e441cb7L10"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L10"></a><span class="line-content"><span class="nd">@hooks</span><span class="o">.</span><span class="n">hook</span><span class="p">()</span></span></span>
<span class="line" id="e441cb7L11"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L11"></a><span class="line-content"><span class="k">def</span><span class="w"> </span><span class="nf">deploy</span><span class="p">(</span><span class="n">data</span><span class="p">):</span></span></span>
<span class="line" id="e441cb7L12"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L12"></a><span class="line-content">    <span class="kn">import</span><span class="w"> </span><span class="nn">subprocess</span></span></span>
<span class="line" id="e441cb7L13"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L13"></a><span class="line-content">    <span class="kn">import</span><span class="w"> </span><span class="nn">threading</span></span></span>
<span class="line" id="e441cb7L14"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L14"></a><span class="line-content"></span></span>
<span class="line" id="e441cb7L15"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L15"></a><span class="line-content">    <span class="kn">import</span><span class="w"> </span><span class="nn">flask</span></span></span>
<span class="line" id="e441cb7L16"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L16"></a><span class="line-content"></span></span>
<span class="line" id="e441cb7L17"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L17"></a><span class="line-content">    <span class="n">LOGGER</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;Got github hook with data: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span></span></span>
<span class="line" id="e441cb7L18"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L18"></a><span class="line-content"></span></span>
<span class="line" id="e441cb7L19"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L19"></a><span class="line-content">    <span class="k">try</span><span class="p">:</span></span></span>
<span class="line" id="e441cb7L20"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L20"></a><span class="line-content">        <span class="n">result</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">check_output</span><span class="p">(</span></span></span>
<span class="line" id="e441cb7L21"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L21"></a><span class="line-content">            <span class="p">[</span><span class="s1">&#39;./deploy.sh&#39;</span><span class="p">,</span> <span class="s1">&#39;nokill&#39;</span><span class="p">],</span></span></span>
<span class="line" id="e441cb7L22"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L22"></a><span class="line-content">            <span class="n">stderr</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">STDOUT</span><span class="p">)</span></span></span>
<span class="line" id="e441cb7L23"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L23"></a><span class="line-content">    <span class="k">except</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">CalledProcessError</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span></span></span>
<span class="line" id="e441cb7L24"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L24"></a><span class="line-content">        <span class="n">LOGGER</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">&quot;Deployment failed: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">err</span><span class="o">.</span><span class="n">output</span><span class="p">)</span></span></span>
<span class="line" id="e441cb7L25"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L25"></a><span class="line-content">        <span class="k">return</span> <span class="n">flask</span><span class="o">.</span><span class="n">Response</span><span class="p">(</span><span class="n">err</span><span class="o">.</span><span class="n">output</span><span class="p">,</span> <span class="n">status_code</span><span class="o">=</span><span class="mi">500</span><span class="p">,</span> <span class="n">mimetype</span><span class="o">=</span><span class="s1">&#39;text/plain&#39;</span><span class="p">)</span></span></span>
<span class="line" id="e441cb7L26"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L26"></a><span class="line-content"></span></span>
<span class="line" id="e441cb7L27"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L27"></a><span class="line-content">    <span class="k">def</span><span class="w"> </span><span class="nf">restart_server</span><span class="p">(</span><span class="n">pid</span><span class="p">):</span></span></span>
<span class="line" id="e441cb7L28"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L28"></a><span class="line-content">        <span class="n">LOGGER</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;Restarting&quot;</span><span class="p">)</span></span></span>
<span class="line" id="e441cb7L29"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L29"></a><span class="line-content">        <span class="n">os</span><span class="o">.</span><span class="n">kill</span><span class="p">(</span><span class="n">pid</span><span class="p">,</span> <span class="n">signal</span><span class="o">.</span><span class="n">SIGHUP</span><span class="p">)</span></span></span>
<span class="line" id="e441cb7L30"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L30"></a><span class="line-content"></span></span>
<span class="line" id="e441cb7L31"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L31"></a><span class="line-content">    <span class="n">LOGGER</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">&quot;Restarting server in 3 seconds...&quot;</span><span class="p">)</span></span></span>
<span class="line" id="e441cb7L32"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L32"></a><span class="line-content">    <span class="n">threading</span><span class="o">.</span><span class="n">Timer</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">restart_server</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">[</span><span class="n">os</span><span class="o">.</span><span class="n">getpid</span><span class="p">()])</span><span class="o">.</span><span class="n">start</span><span class="p">()</span></span></span>
<span class="line" id="e441cb7L33"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L33"></a><span class="line-content"></span></span>
<span class="line" id="e441cb7L34"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#e441cb7L34"></a><span class="line-content">    <span class="k">return</span> <span class="n">flask</span><span class="o">.</span><span class="n">Response</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">mimetype</span><span class="o">=</span><span class="s1">&#39;text/plain&#39;</span><span class="p">)</span></span></span>
</pre></figure><p>Now, set up your deployment to have an environment variable called <code>GITHUB_SECRET</code> set to some random, unguessable string. Do a manual redeployment.</p><p>Finally, go to your GitHub repository settings, then &ldquo;Webhooks,&rdquo; then &ldquo;Add webhook.&rdquo; On the new webhook, set your payload URL to your deployment hook (e.g. <code>http://example.com/_gh</code>), the content type to <code>application/x-www-form-urlencoded</code>, and the secret to the value of your <code>GITHUB_SECRET</code> string. It should look something like this:</p><p><a href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git"><img src="https://publ.beesbuzz.biz/static/_img/82/c8da/github-webhook-setup_397697e53b_320x280.png" width="320" height="280" srcset="https://publ.beesbuzz.biz/static/_img/82/c8da/github-webhook-setup_397697e53b_320x280.png 1x, https://publ.beesbuzz.biz/static/_img/82/c8da/github-webhook-setup_397697e53b_640x559.png 2x" loading="lazy" alt="Configuration settings for the GitHub webhooks"></a></p><p>Anyway, once you have it set up, every time you commit to GitHub, your site should automatically pull and redeploy the latest changes.</p><p>An example of this in action can be seen at the <a href="https://publ.beesbuzz.biz/github-site">files for this site</a>; in particular, see the <a href="https://github.com/PlaidWeb/publ-site/blob/master/app.py"><code>app.py</code></a> and <a href="https://github.com/PlaidWeb/publ-site/blob/master/deploy.sh"><code>deploy.sh</code></a> files.</p><h2 id="441_h2_7_Troubleshooting"><a href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#441_h2_7_Troubleshooting"></a>Troubleshooting</h2><h3 id="441_h3_8_Site-doesn-t-update-or-updates-r"><a href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#441_h3_8_Site-doesn-t-update-or-updates-r"></a>Site doesn&rsquo;t update, or &ldquo;updates rejected&rdquo;</h3><p>This is usually a sign that something changed on your deployment repository that&rsquo;s causing a git conflict. <code>ssh</code> into your live workspace and do a <code>git pull</code> to see what&rsquo;s going on. Chances are there was a change on your live repository that&rsquo;s causing an update conflict, for example you checked in an entry which didn&rsquo;t yet have an assigned <code>Entry-ID</code> or the like.</p><p>Generally you can fix this by going into your live repository and doing <code>git status</code> to see what&rsquo;s changed, and a command like <code>git checkout . &amp;&amp; git pull</code> or <code>git reset --hard origin/master</code> will sort everything out (but be sure not to lose any changes you meant to make directly on the server).</p><h3 id="441_h3_9_Webhook-is-timing-out"><a href="https://publ.beesbuzz.biz/manual/deploying/441-Continuous-deployment-with-git#441_h3_9_Webhook-is-timing-out"></a>Webhook is timing out</h3><p>If your packages change, the webhook will likely time out while <code>poetry install</code> runs. This should be okay, but try <code>ssh</code>ing into your live workspace and running <code>./deploy.sh</code> manually.</p>

]]>
        </content>
    </entry>
    
    <entry>
        <title>Self-hosting Publ</title>
        <link href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ" rel="alternate" type="text/html" />
        <published>2018-12-16T22:41:45-08:00</published>
        <updated>2018-12-16T22:41:45-08:00</updated>
        <id>urn:uuid:6b0d8b5d-08d2-5ad5-8cf0-13a1c5720586</id>
        <author><name>fluffy</name></author>
        <content type="html">
<![CDATA[
<p>How to host Publ on your own webserver</p>

<p>This assumes that you have your own webserver where you can run your site.  There are two parts to this: <a href="https://publ.beesbuzz.biz/manual/deploying/feed#service">running the Publ service</a>, and <a href="https://publ.beesbuzz.biz/manual/deploying/feed#routing">routing public traffic</a> from the fronting webserver (Apache, nginx, fhttpd, etc.) to it.</p><p>This list is not exhaustive; if there is a mechanism that you&rsquo;d like to see supported, feel free to open an <a href="https://publ.beesbuzz.biz/issue-site/">issue</a> or, better yet, <a href="https://github.com/PlaidWeb/Publ-site/pulls">pull request</a> with details!</p><h2 id="1278_h2_1_Running-the-Publ-service"><a href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#1278_h2_1_Running-the-Publ-service"></a><span id="service">Running the Publ service</span></h2><h3 id="1278_h3_2_Prerequisites"><a href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#1278_h3_2_Prerequisites"></a>Prerequisites</h3><p>You will need Python 3. The most reliable way to install this is via <a href="https://github.com/pyenv/pyenv"><code>pyenv</code></a>, but any system-provided Python 3 will do, as long as it meets the minimum system requirements.</p><p>The easiest way to manage your package dependencies is with <a href="https://python-poetry.org"><code>poetry</code></a>; you can see <a href="https://python-poetry.org/docs/#installation">their installation instructions</a> for more information. <code>pipenv</code> and <code>virtualenv</code> also work but these instructions will focus on the use of <code>poetry</code>.</p><p>Your Publ environment needs to have a WSGI server available. <a href="http://gunicorn.org">gunicorn</a> is a good choice for this. The ideal means of installing gunicorn is directly into your site&rsquo;s environment. If you&rsquo;re using <code>poetry</code> then that&rsquo;s done with:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e1278cb1L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb1L1"></a><span class="line-content">poetry<span class="w"> </span>add<span class="w"> </span>gunicorn</span></span>
</pre></figure><p>It will also be helpful to know the full path to the <code>poetry</code> command. You can usually find this with</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e1278cb2L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb2L1"></a><span class="line-content">which<span class="w"> </span>poetry</span></span>
</pre></figure><p>It will typically be <code>$HOME/.poetry/bin/poetry</code>.</p><h3 id="1278_h3_3_Basic-approach"><a href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#1278_h3_3_Basic-approach"></a>Basic approach</h3><p>Anything that runs the application server should change into the site&rsquo;s working directory, and then start the gunicorn process with</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e1278cb3L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb3L1"></a><span class="line-content">/path/to/poetry<span class="w"> </span>run<span class="w"> </span>gunicorn<span class="w"> </span>-b<span class="w"> </span>unix:gunicorn.sock<span class="w"> </span>app:app</span></span>
</pre></figure><p>which will use the <code>app</code> object declared in <code>app.py</code> (per the <a href="https://publ.beesbuzz.biz/manual/328-Getting-started">getting started guide</a>) and listen on a socket file named <code>gunicorn.sock</code>. The presence of that socket file will also indicate whether the site is up and running.</p><p>Note that you don&rsquo;t have to put <code>gunicorn.sock</code> in the same directory as the application &ndash; it can go anywhere that the web server has access. For example, it&rsquo;s nice to make a <code>$HOME/.vhosts</code> directory to keep your socket files, named with the site name:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e1278cb4L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb4L1"></a><span class="line-content">/path/to/poetry<span class="w"> </span>run<span class="w"> </span>gunicorn<span class="w"> </span>-b<span class="w"> </span>unix:/home/USERNAME/.vhosts/example.com<span class="w"> </span>app:app</span></span>
</pre></figure><p>This way you can also set the directory permissions on your site files with <code>chmod 700</code> which prevents other users of the server from peeking into them.</p><h3 id="1278_h3_4_systemd"><a href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#1278_h3_4_systemd"></a><span id="systemd">systemd</span></h3><p>If you&rsquo;re on a UNIX that uses <code>systemd</code> (for example, recent versions of Ubuntu or CentOS), the preferred approach is to run the site as a user service. Here is an example service file:</p><figure class="blockcode"><figcaption> example.com.service</figcaption><pre class="highlight" data-language="systemd" data-line-numbers><span class="line" id="e1278cb5L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb5L1"></a><span class="line-content"><span class="k">[Unit]</span></span></span>
<span class="line" id="e1278cb5L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb5L2"></a><span class="line-content"><span class="na">Description</span><span class="o">=</span><span class="s">Publ instance for example.com</span></span></span>
<span class="line" id="e1278cb5L3"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb5L3"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb5L4"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb5L4"></a><span class="line-content"><span class="k">[Service]</span></span></span>
<span class="line" id="e1278cb5L5"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb5L5"></a><span class="line-content"><span class="na">Restart</span><span class="o">=</span><span class="s">always</span></span></span>
<span class="line" id="e1278cb5L6"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb5L6"></a><span class="line-content"><span class="na">WorkingDirectory</span><span class="o">=</span><span class="s">/home/USERNAME/example.com</span></span></span>
<span class="line" id="e1278cb5L7"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb5L7"></a><span class="line-content"><span class="na">ExecStart</span><span class="o">=</span><span class="s">/path/to/poetry run gunicorn -b unix:/path/to/socket app:app</span></span></span>
<span class="line" id="e1278cb5L8"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb5L8"></a><span class="line-content"><span class="na">ExecReload</span><span class="o">=</span><span class="s">/bin/kill -HUP $MAINPID</span></span></span>
<span class="line" id="e1278cb5L9"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb5L9"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb5L10"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb5L10"></a><span class="line-content"><span class="k">[Install]</span></span></span>
<span class="line" id="e1278cb5L11"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb5L11"></a><span class="line-content"><span class="na">WantedBy</span><span class="o">=</span><span class="s">default.target</span></span></span>
</pre></figure><p>Install this file as e.g. <code>$HOME/.config/systemd/user/example.com.service</code> and then you should be able to start the server with:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e1278cb6L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb6L1"></a><span class="line-content">systemctl<span class="w"> </span>--user<span class="w"> </span><span class="nb">enable</span><span class="w"> </span>example.com</span></span>
<span class="line" id="e1278cb6L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb6L2"></a><span class="line-content">systemctl<span class="w"> </span>--user<span class="w"> </span>start<span class="w"> </span>example.com</span></span>
</pre></figure><p>and the site should now be up and running on the local port; as long as it&rsquo;s up there should be a socket file named <code>gunicorn.sock</code> in the site&rsquo;s directory.</p><p>However, this service will only run while the user is logged in; in order to make it run persistently, have an admin set your user to &ldquo;linger&rdquo; with e.g.:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e1278cb7L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb7L1"></a><span class="line-content">sudo<span class="w"> </span>loginctl<span class="w"> </span>enable-linger<span class="w"> </span>USERNAME</span></span>
</pre></figure><p>Anyway, once you have this service set up, you can use <code>systemctl</code> to do a number of useful things; some example commands:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e1278cb8L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L1"></a><span class="line-content"><span class="c1"># Start the website if it isn&#39;t running</span></span></span>
<span class="line" id="e1278cb8L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L2"></a><span class="line-content">systemctl<span class="w"> </span>--user<span class="w"> </span>start<span class="w"> </span>example.com</span></span>
<span class="line" id="e1278cb8L3"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L3"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb8L4"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L4"></a><span class="line-content"><span class="c1"># Shut off the website temporarily</span></span></span>
<span class="line" id="e1278cb8L5"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L5"></a><span class="line-content">systemctl<span class="w"> </span>--user<span class="w"> </span>stop<span class="w"> </span>example.com</span></span>
<span class="line" id="e1278cb8L6"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L6"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb8L7"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L7"></a><span class="line-content"><span class="c1"># Reload the website (if e.g. templates changed)</span></span></span>
<span class="line" id="e1278cb8L8"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L8"></a><span class="line-content">systemctl<span class="w"> </span>--user<span class="w"> </span>reload-or-restart<span class="w"> </span>example.com</span></span>
<span class="line" id="e1278cb8L9"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L9"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb8L10"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L10"></a><span class="line-content"><span class="c1"># Restart the website (if e.g. Publ or gunicorn gets updated)</span></span></span>
<span class="line" id="e1278cb8L11"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L11"></a><span class="line-content">systemctl<span class="w"> </span>--user<span class="w"> </span>restart<span class="w"> </span>example.com</span></span>
<span class="line" id="e1278cb8L12"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L12"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb8L13"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L13"></a><span class="line-content"><span class="c1"># Disable the website from starting up automatically</span></span></span>
<span class="line" id="e1278cb8L14"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L14"></a><span class="line-content">systemctl<span class="w"> </span>--user<span class="w"> </span>disable<span class="w"> </span>example.com</span></span>
<span class="line" id="e1278cb8L15"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L15"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb8L16"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L16"></a><span class="line-content"><span class="c1"># Enable the website to start up automatically</span></span></span>
<span class="line" id="e1278cb8L17"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L17"></a><span class="line-content">systemctl<span class="w"> </span>--user<span class="w"> </span><span class="nb">enable</span><span class="w"> </span>example.com</span></span>
<span class="line" id="e1278cb8L18"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L18"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb8L19"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L19"></a><span class="line-content"><span class="c1"># Look at the status of the website (and see the logs)</span></span></span>
<span class="line" id="e1278cb8L20"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb8L20"></a><span class="line-content">systemctl<span class="w"> </span>--user<span class="w"> </span>status<span class="w"> </span>example.com</span></span>
</pre></figure><p>See the <a href="https://www.freedesktop.org/software/systemd/man/systemctl.html"><code>systemctl</code> manual page</a> for more infromation.</p><h3 id="1278_h3_5_Other-watchdog-services"><a href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#1278_h3_5_Other-watchdog-services"></a>Other watchdog services</h3><p>Some Linux distributions provide other mechanisms for running persistent services under a watchdog, such as <a href="https://cr.yp.to/daemontools.html">daemontools</a> or <a href="https://upstart.ubuntu.com/">upstart</a>. These mechanisms are not highly recommended.</p><h3 id="1278_h3_6_cron"><a href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#1278_h3_6_cron"></a>cron</h3><p>In a pinch, you can use a <a href="https://en.wikipedia.org/wiki/Cron">cron job</a> as a makeshift supervisor; create a file named <code>cron-launcher.sh</code> in your site directory:</p><figure class="blockcode"><figcaption> cron-launcher.sh</figcaption><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e1278cb9L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb9L1"></a><span class="line-content"><span class="ch">#!/bin/sh</span></span></span>
<span class="line" id="e1278cb9L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb9L2"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb9L3"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb9L3"></a><span class="line-content"><span class="nb">cd</span><span class="w"> </span><span class="k">$(</span>dirname<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$0</span><span class="s2">&quot;</span><span class="k">)</span></span></span>
<span class="line" id="e1278cb9L4"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb9L4"></a><span class="line-content">flock<span class="w"> </span>-n<span class="w"> </span>.lockfile<span class="w"> </span>/path/to/poetry<span class="w"> </span>run<span class="w"> </span>gunicorn<span class="w"> </span>-b<span class="w"> </span>unix:gunicorn.sock<span class="w"> </span>app:app</span></span>
</pre></figure><p>and then run <code>crontab -e</code> and add a line like:</p><figure class="blockcode"><pre class="highlight" data-language="crontab" data-line-numbers><span class="line" id="e1278cb10L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb10L1"></a><span class="line-content">* * * * * /home/USERNAME/example.com/cron-launcher.sh</span></span>
</pre></figure><h3 id="1278_h3_7_Next-steps"><a href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#1278_h3_7_Next-steps"></a>Next steps</h3><p>You can verify that the site is working with <code>curl</code>; for example:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e1278cb11L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb11L1"></a><span class="line-content">curl<span class="w"> </span>--unix-socket<span class="w"> </span>gunicorn.sock<span class="w"> </span>https://example.com/</span></span>
</pre></figure><p>By default, <code>gunicorn</code> only runs with a small number of render threads. You might want to increase this with the <code>--threads</code> parameter, e.g.:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e1278cb12L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb12L1"></a><span class="line-content">/path/to/poetry<span class="w"> </span>run<span class="w"> </span>gunicorn<span class="w"> </span>--threads<span class="w"> </span><span class="m">8</span><span class="w"> </span>-b<span class="w"> </span>unix:/path/to/socket<span class="w"> </span>app:app</span></span>
</pre></figure><p>The number of threads to use varies greatly. You almost certainly want more than 1 thread (especially if you&rsquo;re planning on using authentication), but overallocating on threads can cause other problems to happen in some circumstances. I find that even for larger sites, a thread count of 8-12 is more than sufficient.</p><h2 id="1278_h2_8_Routing-traffic"><a href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#1278_h2_8_Routing-traffic"></a><span id="routing">Routing traffic</span></h2><p>Configuring Publ to work with your web server is a matter of configuring the fronting httpd as a proxy to your Publ instance&rsquo;s socket. The two most common are <a href="https://apache.org/">Apache</a> and <a href="https://nginx.com/">nginx</a>, but there are others as well.</p><h3 id="1278_h3_9_Apache"><a href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#1278_h3_9_Apache"></a>Apache</h3><p>To use this with Apache, you&rsquo;ll need <code>mod_proxy</code> installed and enabled.</p><p>Next, you&rsquo;ll need to configure a vhost to forward your domain&rsquo;s traffic to the gunicorn socket. Here is a basic Apache configuration (e.g. <code>/etc/apache2/sites-enabled/100-example.com.conf</code>), showing how to configure both <code>http</code> and <code>https</code>:</p><figure class="blockcode"><pre class="highlight" data-language="apache" data-line-numbers><span class="line" id="e1278cb13L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L1"></a><span class="line-content"><span class="c"># http</span></span></span>
<span class="line" id="e1278cb13L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L2"></a><span class="line-content"><span class="nt">&lt;VirtualHost</span><span class="w"> </span><span class="s">*:80</span><span class="nt">&gt;</span></span></span>
<span class="line" id="e1278cb13L3"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L3"></a><span class="line-content"><span class="w">    </span><span class="nb">ServerName</span><span class="w"> </span>example.com</span></span>
<span class="line" id="e1278cb13L4"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L4"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb13L5"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L5"></a><span class="line-content"><span class="w">    </span><span class="nb">AcceptPathInfo</span><span class="w"> </span><span class="k">On</span></span></span>
<span class="line" id="e1278cb13L6"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L6"></a><span class="line-content"><span class="w">    </span><span class="nb">ErrorLog</span><span class="w"> </span><span class="sx">/path/to/error.log</span></span></span>
<span class="line" id="e1278cb13L7"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L7"></a><span class="line-content"><span class="w">    </span><span class="nb">CustomLog</span><span class="w"> </span><span class="sx">/path/to/access.log</span><span class="w"> </span>combined</span></span>
<span class="line" id="e1278cb13L8"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L8"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb13L9"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L9"></a><span class="line-content"><span class="w">    </span><span class="nt">&lt;Proxy</span><span class="w"> </span><span class="s">*</span><span class="nt">&gt;</span></span></span>
<span class="line" id="e1278cb13L10"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L10"></a><span class="line-content"><span class="w">        </span><span class="nb">Order</span><span class="w"> </span>deny,allow</span></span>
<span class="line" id="e1278cb13L11"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L11"></a><span class="line-content"><span class="w">        </span><span class="nb">Allow</span><span class="w"> </span>from<span class="w"> </span><span class="k">all</span></span></span>
<span class="line" id="e1278cb13L12"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L12"></a><span class="line-content"><span class="w">    </span><span class="nt">&lt;/Proxy&gt;</span></span></span>
<span class="line" id="e1278cb13L13"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L13"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb13L14"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L14"></a><span class="line-content"><span class="w">    </span><span class="nb">ProxyPreserveHost</span><span class="w"> </span><span class="k">On</span></span></span>
<span class="line" id="e1278cb13L15"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L15"></a><span class="line-content"><span class="w">    </span><span class="nb">ProxyPass</span><span class="w"> </span>/<span class="w"> </span>unix:/user/USERNAME/example.com/gunicorn.sock|http://localhost/</span></span>
<span class="line" id="e1278cb13L16"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L16"></a><span class="line-content"><span class="nt">&lt;/VirtualHost&gt;</span></span></span>
<span class="line" id="e1278cb13L17"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L17"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb13L18"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L18"></a><span class="line-content"><span class="c"># https</span></span></span>
<span class="line" id="e1278cb13L19"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L19"></a><span class="line-content"><span class="nt">&lt;IfModule</span><span class="w"> </span><span class="s">mod_ssl.c</span><span class="nt">&gt;</span></span></span>
<span class="line" id="e1278cb13L20"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L20"></a><span class="line-content"><span class="nt">&lt;VirtualHost</span><span class="w"> </span><span class="s">*:443</span><span class="nt">&gt;</span></span></span>
<span class="line" id="e1278cb13L21"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L21"></a><span class="line-content"><span class="w">    </span><span class="nb">ServerName</span><span class="w"> </span>example.com</span></span>
<span class="line" id="e1278cb13L22"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L22"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb13L23"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L23"></a><span class="line-content"><span class="w">    </span><span class="nb">AcceptPathInfo</span><span class="w"> </span><span class="k">On</span></span></span>
<span class="line" id="e1278cb13L24"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L24"></a><span class="line-content"><span class="w">    </span><span class="nb">ErrorLog</span><span class="w"> </span><span class="sx">/path/to/ssl-error.log</span></span></span>
<span class="line" id="e1278cb13L25"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L25"></a><span class="line-content"><span class="w">    </span><span class="nb">CustomLog</span><span class="w"> </span><span class="sx">/path/to/ssl-access.log</span><span class="w"> </span>combined</span></span>
<span class="line" id="e1278cb13L26"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L26"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb13L27"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L27"></a><span class="line-content"><span class="w">    </span><span class="nt">&lt;Proxy</span><span class="w"> </span><span class="s">*</span><span class="nt">&gt;</span></span></span>
<span class="line" id="e1278cb13L28"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L28"></a><span class="line-content"><span class="w">        </span><span class="nb">Order</span><span class="w"> </span>deny,allow</span></span>
<span class="line" id="e1278cb13L29"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L29"></a><span class="line-content"><span class="w">        </span><span class="nb">Allow</span><span class="w"> </span>from<span class="w"> </span><span class="k">all</span></span></span>
<span class="line" id="e1278cb13L30"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L30"></a><span class="line-content"><span class="w">    </span><span class="nt">&lt;/Proxy&gt;</span></span></span>
<span class="line" id="e1278cb13L31"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L31"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb13L32"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L32"></a><span class="line-content"><span class="w">    </span><span class="nb">ProxyPreserveHost</span><span class="w"> </span><span class="k">On</span></span></span>
<span class="line" id="e1278cb13L33"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L33"></a><span class="line-content"><span class="w">    </span><span class="nb">ProxyPass</span><span class="w"> </span>/<span class="w"> </span>unix:/user/USERNAME/example.com/gunicorn.sock|http://localhost/</span></span>
<span class="line" id="e1278cb13L34"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L34"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb13L35"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L35"></a><span class="line-content"><span class="w">    </span><span class="c"># tell gunicorn that this is https instead of http</span></span></span>
<span class="line" id="e1278cb13L36"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L36"></a><span class="line-content"><span class="w">    </span><span class="nb">RequestHeader</span><span class="w"> </span>set<span class="w"> </span>X-Forwarded-Proto<span class="w"> </span>https</span></span>
<span class="line" id="e1278cb13L37"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L37"></a><span class="line-content"><span class="w">    </span><span class="nb">SSLCertificateFile</span><span class="w"> </span><span class="sx">/path/to/fullchain.pem</span></span></span>
<span class="line" id="e1278cb13L38"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L38"></a><span class="line-content"><span class="w">    </span><span class="nb">SSLCertificateKeyFile</span><span class="w"> </span><span class="sx">/path/to/privkey.pem</span></span></span>
<span class="line" id="e1278cb13L39"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L39"></a><span class="line-content"><span class="nt">&lt;/VirtualHost&gt;</span></span></span>
<span class="line" id="e1278cb13L40"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb13L40"></a><span class="line-content"><span class="nt">&lt;/IfModule&gt;</span></span></span>
</pre></figure><p>Note that both connections go over the same socket; you can have arbitrarily many fronting configurations to the same Publ instance, even with different domain names! Publ doesn&rsquo;t mind at all.</p><p>If you use <a href="http://letsencrypt.org/">Let&rsquo;s Encrypt</a> to manage your SSL certificate, the configuration change made by <code>certbot --apache</code> <em>should</em> &ldquo;just work&rdquo; although you will want to make sure that it sets <code>X-Forwarded-Protocol</code> or else Publ will still generate <code>http://</code> URLs for things, which is probably not what you want.</p><h3 id="1278_h3_10_nginx"><a href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#1278_h3_10_nginx"></a>nginx</h3><p>Here is an example nginx configuration, e.g. <code>/etc/nginx/sites-available/example.com</code>:</p><figure class="blockcode"><pre class="highlight" data-language="nginx" data-line-numbers><span class="line" id="e1278cb14L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L1"></a><span class="line-content"><span class="c1"># http</span></span></span>
<span class="line" id="e1278cb14L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L2"></a><span class="line-content"><span class="k">server</span><span class="w"> </span><span class="p">{</span></span></span>
<span class="line" id="e1278cb14L3"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L3"></a><span class="line-content"><span class="w">    </span><span class="kn">listen</span><span class="w"> </span><span class="mi">80</span><span class="p">;</span></span></span>
<span class="line" id="e1278cb14L4"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L4"></a><span class="line-content"><span class="w">    </span><span class="kn">server_name</span><span class="w"> </span><span class="s">example.com</span><span class="p">;</span></span></span>
<span class="line" id="e1278cb14L5"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L5"></a><span class="line-content"><span class="w">    </span><span class="kn">access_log</span><span class="w">  </span><span class="s">/var/log/nginx/example.log</span><span class="p">;</span></span></span>
<span class="line" id="e1278cb14L6"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L6"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb14L7"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L7"></a><span class="line-content"><span class="w">    </span><span class="kn">location</span><span class="w"> </span><span class="s">/</span><span class="w"> </span><span class="p">{</span></span></span>
<span class="line" id="e1278cb14L8"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L8"></a><span class="line-content"><span class="w">        </span><span class="kn">proxy_pass</span><span class="w"> </span><span class="s">http://unix:/path/to/gunicorn.sock:/</span><span class="p">;</span></span></span>
<span class="line" id="e1278cb14L9"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L9"></a><span class="line-content"><span class="w">        </span><span class="kn">proxy_set_header</span><span class="w"> </span><span class="s">Host</span><span class="w"> </span><span class="nv">$host</span><span class="p">;</span></span></span>
<span class="line" id="e1278cb14L10"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L10"></a><span class="line-content"><span class="w">        </span><span class="kn">proxy_set_header</span><span class="w"> </span><span class="s">X-Forwarded-For</span><span class="w"> </span><span class="nv">$proxy_add_x_forwarded_for</span><span class="p">;</span></span></span>
<span class="line" id="e1278cb14L11"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L11"></a><span class="line-content"><span class="w">        </span><span class="kn">proxy_set_header</span><span class="w"> </span><span class="s">X-Forwarded-Proto</span><span class="w"> </span><span class="nv">$scheme</span><span class="p">;</span></span></span>
<span class="line" id="e1278cb14L12"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L12"></a><span class="line-content"><span class="w">    </span><span class="p">}</span></span></span>
<span class="line" id="e1278cb14L13"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L13"></a><span class="line-content"><span class="p">}</span></span></span>
<span class="line" id="e1278cb14L14"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L14"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb14L15"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L15"></a><span class="line-content"><span class="c1">#https</span></span></span>
<span class="line" id="e1278cb14L16"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L16"></a><span class="line-content"><span class="k">server</span><span class="w"> </span><span class="p">{</span></span></span>
<span class="line" id="e1278cb14L17"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L17"></a><span class="line-content"><span class="w">    </span><span class="kn">listen</span><span class="w"> </span><span class="mi">443</span><span class="p">;</span></span></span>
<span class="line" id="e1278cb14L18"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L18"></a><span class="line-content"><span class="w">    </span><span class="kn">server_name</span><span class="w"> </span><span class="s">example.com</span><span class="p">;</span></span></span>
<span class="line" id="e1278cb14L19"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L19"></a><span class="line-content"><span class="w">    </span><span class="kn">access_log</span><span class="w">  </span><span class="s">/var/log/nginx/example.log</span><span class="p">;</span></span></span>
<span class="line" id="e1278cb14L20"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L20"></a><span class="line-content"><span class="w">    </span><span class="kn">ssl_certificate</span><span class="w">     </span><span class="s">/path/to/fullchain.pem</span><span class="p">;</span></span></span>
<span class="line" id="e1278cb14L21"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L21"></a><span class="line-content"><span class="w">    </span><span class="kn">ssl_certificate_key</span><span class="w"> </span><span class="s">/path/to/privkey.pem</span><span class="p">;</span></span></span>
<span class="line" id="e1278cb14L22"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L22"></a><span class="line-content"></span></span>
<span class="line" id="e1278cb14L23"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L23"></a><span class="line-content"><span class="w">    </span><span class="kn">location</span><span class="w"> </span><span class="s">/</span><span class="w"> </span><span class="p">{</span></span></span>
<span class="line" id="e1278cb14L24"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L24"></a><span class="line-content"><span class="w">        </span><span class="kn">proxy_pass</span><span class="w"> </span><span class="s">http://unix:/path/to/gunicorn.sock:/</span><span class="p">;</span></span></span>
<span class="line" id="e1278cb14L25"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L25"></a><span class="line-content"><span class="w">        </span><span class="kn">proxy_set_header</span><span class="w"> </span><span class="s">Host</span><span class="w"> </span><span class="nv">$host</span><span class="p">;</span></span></span>
<span class="line" id="e1278cb14L26"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L26"></a><span class="line-content"><span class="w">        </span><span class="kn">proxy_set_header</span><span class="w"> </span><span class="s">X-Forwarded-For</span><span class="w"> </span><span class="nv">$proxy_add_x_forwarded_for</span><span class="p">;</span></span></span>
<span class="line" id="e1278cb14L27"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L27"></a><span class="line-content"><span class="w">        </span><span class="kn">proxy_set_header</span><span class="w"> </span><span class="s">X-Forwarded-Proto</span><span class="w"> </span><span class="nv">$scheme</span><span class="p">;</span></span></span>
<span class="line" id="e1278cb14L28"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L28"></a><span class="line-content"><span class="w">    </span><span class="p">}</span></span></span>
<span class="line" id="e1278cb14L29"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#e1278cb14L29"></a><span class="line-content"><span class="p">}</span></span></span>
</pre></figure><h3 id="1278_h3_11_Others"><a href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#1278_h3_11_Others"></a>Others</h3><p>The basic premise to configuring any arbitrary httpd to work with Publ:</p>
<ul>
<li>Reverse proxy from your vhost to the UNIX socket (or <code>localhost</code> port, if UNIX sockets aren&rsquo;t supported)</li>
<li>On SSL, add <code>X-Forwarded-Proto $scheme</code></li>
<li>Try to preserve the incoming <code>Host</code> and set <code>X-Forwarded-For</code> if at all possible</li>
</ul>
<p>If these are not options, you could see if there is direct support for WSGI from the server instead. However, this usually has security implications, especially with regards to how the image rendition cache works; running as a reverse proxy is almost always the preferred approach.</p><h2 id="1278_h2_12_Alternatives-to-gunicorn"><a href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#1278_h2_12_Alternatives-to-gunicorn"></a>Alternatives to gunicorn</h2><h3 id="1278_h3_13_hypercorn"><a href="https://publ.beesbuzz.biz/manual/deploying/1278-Self-hosting-Publ#1278_h3_13_hypercorn"></a><a href="https://hypercorn.readthedocs.io/">hypercorn</a></h3><p>In some situations, hypercorn has better scaling characteristics than gunicorn. However, it isn&rsquo;t quite as turnkey as gunicorn, as it defaults to tighter security regarding proxies. So, in order to use it with hypercorn, the following changes must be made to your deployment:</p>
<ol>
<li><p>In order to set the correct socket permissions, either launch it with <code>-m 0</code> (giving it the same wide permissions as gunicorn), or ensure that your user shares a group with the webserver process and set that as the parameter to <code>-g</code>. My recommendation is to just use <code>-m 0</code>, e.g.</p><figure class="blockcode"><pre><span class="line"><span class="line-content">poetry run gunicorn -b unix:/path/to/socket -m 0 app:app</span></span>
</pre></figure></li>
<li><p>In order to correctly handle the <code>X-Forwarded-*</code> headers, add these lines to the bottom of your <code>app.py</code>:</p><figure class="blockcode"><pre><span class="line"><span class="line-content">from werkzeug.middleware.proxy_fix import ProxyFix</span></span>
<span class="line"><span class="line-content"></span></span>
<span class="line"><span class="line-content">app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1)</span></span>
</pre></figure><p>This should <em>only</em> be done if Publ is running behind a fronting proxy; while this is the most common deployment scenario, it is not universal, so Publ does not ship with this enabled by default.</p><p>Additionally, the numbers may need to be adjusted if Publ is running behind multiple forwarding proxies; see <a href="https://flask.palletsprojects.com/en/stable/deploying/proxy_fix/">the Flask documentation</a> for more information.</p></li>
</ol>


]]>
        </content>
    </entry>
    
    <entry>
        <title>Heroku</title>
        <link href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku" rel="alternate" type="text/html" />
        <published>2018-10-13T14:23:23-07:00</published>
        <updated>2018-10-13T14:23:23-07:00</updated>
        <id>urn:uuid:5744383f-5712-5011-9a9d-1b3c9806e090</id>
        <author><name>fluffy</name></author>
        <content type="html">
<![CDATA[
<p>How to deploy a Publ website using <a href="http://heroku.com">Heroku</a></p>

<p>Heroku is probably the easiest environment to configure for Publ, especially for
smaller websites. However, it is primarily intended for experimenting with Publ. Heroku comes with a number of limitations:</p>
<ul>
<li>Your git deployment size must be <a href="https://devcenter.heroku.com/articles/limits#git-repos">under 1 GB</a></li>
<li>Your slug size must be <a href="https://devcenter.heroku.com/articles/limits#slug-size">under the 500MB Heroku limit</a></li>
<li>SQLite databases will not persist across site deployments, requiring a full reindex every time your site changes</li>
<li>You can use a Postgres database instead but this causes a (very) slight performance hit on page loads</li>
</ul>
<p>That said, Heroku is a great platform for running a smaller Publ site. Additionally, on the higher tiers you get some nice features like automatic load-balancing and staged deployments. Which is probably overkill for the sites you&rsquo;re running Publ for, but it&rsquo;s still nice to have.</p><h3 id="1210_h3_1_Prerequisites"><a href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#1210_h3_1_Prerequisites"></a>Prerequisites</h3><p>You&rsquo;ll need a <a href="http://heroku.com/">Heroku</a> account, of course, and you&rsquo;ll want to go through their <a href="https://devcenter.heroku.com/articles/getting-started-with-python">Python introduction</a> to get your local environment configured.</p><p>This also assumes you are using a git repository to manage your website files.</p><h3 id="1210_h3_2_Setting-up-your-site-files"><a href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#1210_h3_2_Setting-up-your-site-files"></a>Setting up your site files</h3><p>The easiest way to configure Heroku is using <code>pipenv</code> and <code>gunicorn</code>. Assuming you have a local test version of your site on your computer, do the following:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e1210cb1L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb1L1"></a><span class="line-content"><span class="nb">cd</span><span class="w"> </span>WEBSITE_DIRECTORY</span></span>
<span class="line" id="e1210cb1L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb1L2"></a><span class="line-content">pipenv<span class="w"> </span>--three<span class="w"> </span>install<span class="w"> </span>Publ<span class="w"> </span>gunicorn</span></span>
</pre></figure><p>This will install all of the deployment requirements for Heroku, and configure them in your <code>Pipfile</code> and <code>Pipfile.lock</code>. Check these files into your git repository.</p><p>At this point you should be able to run it locally with:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e1210cb2L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb2L1"></a><span class="line-content">pipenv<span class="w"> </span>run<span class="w"> </span>gunicorn<span class="w"> </span>app:app</span></span>
</pre></figure><p>and connecting to the URL gunicorn tells you (likely <code>http://127.0.0.1:8000/</code>).</p><p>Next, you&rsquo;ll need a <code>Procfile</code> which tells Heroku how to launch your site:</p><figure class="blockcode"><pre class="highlight" data-language="text" data-line-numbers><span class="line" id="e1210cb3L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb3L1"></a><span class="line-content">web: gunicorn app:app</span></span>
</pre></figure><p>Check this file in as well.</p><h3 id="1210_h3_3_Setting-up-Heroku"><a href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#1210_h3_3_Setting-up-Heroku"></a>Setting up Heroku</h3><p>Now you should be ready to deploy! You&rsquo;ll need to create your Heroku app and add the git remote to your site&rsquo;s git repository with e.g.:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e1210cb4L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb4L1"></a><span class="line-content">heroku<span class="w"> </span>create</span></span>
<span class="line" id="e1210cb4L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb4L2"></a><span class="line-content">heroku<span class="w"> </span>git:remote<span class="w"> </span>-a<span class="w"> </span>NAME_OF_APP</span></span>
</pre></figure><p>replacing <code>NAME_OF_APP</code> with whatever name <code>heroku create</code> gave you.</p><p>Deploying to Heroku is now as simple as:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e1210cb5L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb5L1"></a><span class="line-content">git<span class="w"> </span>push<span class="w"> </span>heroku</span></span>
</pre></figure><p>You may also want to run <code>heroku logs --tail</code> to watch its progress.</p><h3 id="1210_h3_4_Database-persistence"><a href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#1210_h3_4_Database-persistence"></a>Database persistence</h3><p>As mentioned above, most of the website startup time is taken up by the initial content index. Since Heroku does not persist your filesystem, you might want to consider using a Postgres database to store the index persistently. Note that this <em>will</em> slow your site down a little bit (since accessing an in-process SQLite database is faster than going over the network to talk to Postgres), but it reduces the amount of site downtime during a content update so that might be a worthwhile tradeoff depending on your needs.</p><p>This slowdown can also be mitigated by increasing your cache timeout; since the site will be redeployed whenever content updates, the cache timeout really only affects how soon scheduled posts will appear after they are set to go live.</p><p>To provision a Postgres database at the free tier, from your local git repository, type the following:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e1210cb6L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb6L1"></a><span class="line-content">heroku<span class="w"> </span>addons:create<span class="w"> </span>heroku-postgresql:hobby-dev</span></span>
</pre></figure><p>This creates a database and then exports it to your environment as <code>DATABASE_URL</code>. Unfortunately, PonyORM does not <em>quite</em> directly support database connection URLs, so we need to do a bit more work on our end. Namely, in <code>app.py</code>, change the <code>database_config</code> part to the following:</p><figure class="blockcode"><pre class="highlight" data-language="python" data-line-numbers><span class="line" id="e1210cb7L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb7L1"></a><span class="line-content"><span class="kn">from</span><span class="w"> </span><span class="nn">urllib.parse</span><span class="w"> </span><span class="kn">import</span> <span class="n">urlparse</span></span></span>
<span class="line" id="e1210cb7L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb7L2"></a><span class="line-content"></span></span>
<span class="line" id="e1210cb7L3"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb7L3"></a><span class="line-content"><span class="n">config</span> <span class="o">=</span> <span class="p">{</span></span></span>
<span class="line" id="e1210cb7L4"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb7L4"></a><span class="line-content">    <span class="s1">&#39;database_config&#39;</span><span class="p">:</span> <span class="p">{</span></span></span>
<span class="line" id="e1210cb7L5"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb7L5"></a><span class="line-content">        <span class="s1">&#39;provider&#39;</span><span class="p">:</span> <span class="n">urlparse</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s1">&#39;DATABASE_URL&#39;</span><span class="p">])</span><span class="o">.</span><span class="n">scheme</span><span class="p">,</span></span></span>
<span class="line" id="e1210cb7L6"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb7L6"></a><span class="line-content">        <span class="s1">&#39;dsn&#39;</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s1">&#39;DATABASE_URL&#39;</span><span class="p">]</span></span></span>
<span class="line" id="e1210cb7L7"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb7L7"></a><span class="line-content">    <span class="p">}</span> <span class="k">if</span> <span class="s1">&#39;DATABASE_URL&#39;</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span> <span class="k">else</span> <span class="p">{</span></span></span>
<span class="line" id="e1210cb7L8"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb7L8"></a><span class="line-content">        <span class="s1">&#39;provider&#39;</span><span class="p">:</span> <span class="s1">&#39;sqlite&#39;</span><span class="p">,</span></span></span>
<span class="line" id="e1210cb7L9"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb7L9"></a><span class="line-content">        <span class="s1">&#39;filename&#39;</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">APP_PATH</span><span class="p">,</span> <span class="s1">&#39;index.db&#39;</span><span class="p">)</span></span></span>
<span class="line" id="e1210cb7L10"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb7L10"></a><span class="line-content">    <span class="p">},</span></span></span>
<span class="line" id="e1210cb7L11"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb7L11"></a><span class="line-content"><span class="p">}</span></span></span>
</pre></figure><p>A full example can be seen in the <a href="https://github.com/PlaidWeb/publ-site/blob/master/app.py"><code>app.py</code> for this site&rsquo;s repository</a>.</p><p>You will also need to install the <code>psycopg2</code> library; this is simply:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e1210cb8L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb8L1"></a><span class="line-content">pipenv<span class="w"> </span>install<span class="w"> </span>psycopg2</span></span>
</pre></figure><p>If you get an error about it failing to install (accompanied with a gigantic log) you might try pinning the version:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e1210cb9L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb9L1"></a><span class="line-content">pipenv<span class="w"> </span>install<span class="w"> </span><span class="s1">&#39;psycopg2&lt;2.8&#39;</span></span></span>
</pre></figure><p>For local testing (to make sure everything is wired up correctly) you can do:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e1210cb10L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/1210-Heroku#e1210cb10L1"></a><span class="line-content"><span class="nv">DATABASE_URL</span><span class="o">=</span><span class="sb">`</span>heroku<span class="w"> </span>config:get<span class="w"> </span>DATABASE_URL<span class="sb">`</span><span class="w"> </span>pipenv<span class="w"> </span>run<span class="w"> </span>gunicorn<span class="w"> </span>app:app</span></span>
</pre></figure><p>although be advised that the database scan will be <em>much</em> slower than in production.</p>

]]>
        </content>
    </entry>
    
    <entry>
        <title>Passenger</title>
        <link href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger" rel="alternate" type="text/html" />
        <published>2018-04-03T02:22:07-07:00</published>
        <updated>2018-04-03T02:22:07-07:00</updated>
        <id>urn:uuid:45e36baf-9c9a-40bf-9af7-1cbacefda9bd</id>
        <author><name>fluffy</name></author>
        <content type="html">
<![CDATA[
<p>How to run Publ on a Passenger environment (including Dreamhost)</p>

<p>Deployment using <a href="https://www.phusionpassenger.com/library/walkthroughs/start/python.html">Phusion Passenger</a> (also known as Passenger WSGI) is fairly straightforward, once you have a python3
environment working. However, on some web hosts, setting up python3 isn&rsquo;t quite obvious.</p><h3 id="326_h3_1_Building-Python-3"><a href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#326_h3_1_Building-Python-3"></a>Building Python 3</h3><p>First you need a Python 3 environment. If your hosting provider doesn&rsquo;t provide one (you can check by running <code>python3</code> from the command line), there are a few ways to install it yourself.</p><p>The easiest way is to use <a href="https://github.com/pyenv/pyenv">pyenv</a>:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e326cb1L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb1L1"></a><span class="line-content">curl<span class="w"> </span>https://pyenv.run<span class="w"> </span><span class="p">|</span><span class="w"> </span>bash</span></span>
<span class="line" id="e326cb1L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb1L2"></a><span class="line-content"><span class="nb">exec</span><span class="w"> </span><span class="nv">$SHELL</span></span></span>
<span class="line" id="e326cb1L3"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb1L3"></a><span class="line-content">pyenv<span class="w"> </span>update</span></span>
<span class="line" id="e326cb1L4"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb1L4"></a><span class="line-content">pyenv<span class="w"> </span>install<span class="w"> </span><span class="m">3</span>.7.6</span></span>
</pre></figure><p>After a while you should be able to verify that you have a working Python 3 installation with e.g.</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e326cb2L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb2L1"></a><span class="line-content">python3<span class="w"> </span>--version</span></span>
<span class="line" id="e326cb2L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb2L2"></a><span class="line-content">pip3<span class="w"> </span>--version</span></span>
</pre></figure><p>If all worked well, you can now install <code>pipenv</code>:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e326cb3L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb3L1"></a><span class="line-content">pip3<span class="w"> </span>install<span class="w"> </span>--user<span class="w"> </span>pipenv</span></span>
</pre></figure><p>and, optionally, add this line to your <code>~/.bash_profile</code> to get better shell
tab completion:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e326cb4L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb4L1"></a><span class="line-content"><span class="nb">eval</span><span class="w"> </span><span class="s2">&quot;</span><span class="k">$(</span>pipenv<span class="w"> </span>--completion<span class="k">)</span><span class="s2">&quot;</span></span></span>
</pre></figure><h3 id="326_h3_2_Set-up-the-virtual-environment"><a href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#326_h3_2_Set-up-the-virtual-environment"></a>Set up the virtual environment</h3><p>Now it&rsquo;s time to set up your virtual environment for Publ. Again, <code>ssh</code> to your webhost and do the following:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e326cb5L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb5L1"></a><span class="line-content"><span class="nb">cd</span><span class="w"> </span><span class="o">(</span>website_directory<span class="o">)</span></span></span>
<span class="line" id="e326cb5L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb5L2"></a><span class="line-content">pipenv<span class="w"> </span>--three</span></span>
<span class="line" id="e326cb5L3"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb5L3"></a><span class="line-content">pipenv<span class="w"> </span>install<span class="w"> </span>Publ</span></span>
</pre></figure><p>This sets up the virtual environment and installs Publ and its dependencies. Now you need to write a <code>passenger_wsgi.py</code> script that tells Passenger how to run it. A fuller example is in the <a href="https://publ.beesbuzz.biz/github-site">files for this site</a> but a minimal version is below:</p><figure class="blockcode"><pre class="highlight" data-language="python" data-line-numbers><span class="line" id="e326cb6L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb6L1"></a><span class="line-content"><span class="kn">import</span><span class="w"> </span><span class="nn">sys</span></span></span>
<span class="line" id="e326cb6L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb6L2"></a><span class="line-content"><span class="kn">import</span><span class="w"> </span><span class="nn">os</span></span></span>
<span class="line" id="e326cb6L3"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb6L3"></a><span class="line-content"><span class="kn">import</span><span class="w"> </span><span class="nn">subprocess</span></span></span>
<span class="line" id="e326cb6L4"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb6L4"></a><span class="line-content"></span></span>
<span class="line" id="e326cb6L5"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb6L5"></a><span class="line-content"><span class="n">INTERP</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">check_output</span><span class="p">(</span></span></span>
<span class="line" id="e326cb6L6"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb6L6"></a><span class="line-content">    <span class="p">[</span><span class="s1">&#39;pipenv&#39;</span><span class="p">,</span> <span class="s1">&#39;run&#39;</span><span class="p">,</span> <span class="s1">&#39;which&#39;</span><span class="p">,</span> <span class="s1">&#39;python3&#39;</span><span class="p">])</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">&#39;utf-8&#39;</span><span class="p">)</span></span></span>
<span class="line" id="e326cb6L7"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb6L7"></a><span class="line-content"><span class="k">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">executable</span> <span class="o">!=</span> <span class="n">INTERP</span><span class="p">:</span></span></span>
<span class="line" id="e326cb6L8"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb6L8"></a><span class="line-content">    <span class="n">os</span><span class="o">.</span><span class="n">execl</span><span class="p">(</span><span class="n">INTERP</span><span class="p">,</span> <span class="n">INTERP</span><span class="p">,</span> <span class="o">*</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span></span></span>
<span class="line" id="e326cb6L9"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb6L9"></a><span class="line-content"></span></span>
<span class="line" id="e326cb6L10"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb6L10"></a><span class="line-content"><span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">())</span></span></span>
<span class="line" id="e326cb6L11"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb6L11"></a><span class="line-content"></span></span>
<span class="line" id="e326cb6L12"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb6L12"></a><span class="line-content"><span class="kn">from</span><span class="w"> </span><span class="nn">main</span><span class="w"> </span><span class="kn">import</span> <span class="n">app</span> <span class="k">as</span> <span class="n">application</span></span></span>
</pre></figure><h3 id="326_h3_3_Configure-the-website"><a href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#326_h3_3_Configure-the-website"></a>Configure the website</h3><p>Once you get your files on your server, it&rsquo;s generally a matter of telling Passenger where to find the files.
Generally, this involves going to your web host&rsquo;s configuration panel and configuring your website to use Passenger.
Different hosts may have different requirements. Known configurations are below:</p><h4 id="326_h4_4_Dreamhost"><a href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#326_h4_4_Dreamhost"></a>Dreamhost</h4><p>Configure your web domain as follows:</p>
<ul>
<li>Web directory: <code>/home/(username)/(site file directory)/public</code></li>
<li>HTTPS (via LetsEncrypt): Yes</li>
<li>Passenger (Ruby/NodeJS/Python apps only): Yes</li>
</ul>
<p>You will also need to have a <code>public</code> directory, ideally with a symbolic link to your <code>static</code> directory inside of it; you can set this up by logging in and doing something like:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e326cb7L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb7L1"></a><span class="line-content"><span class="nb">cd</span><span class="w"> </span><span class="o">(</span>website_directory<span class="o">)</span></span></span>
<span class="line" id="e326cb7L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb7L2"></a><span class="line-content">mkdir<span class="w"> </span>-p<span class="w"> </span>public</span></span>
<span class="line" id="e326cb7L3"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb7L3"></a><span class="line-content"><span class="nb">cd</span><span class="w"> </span>public</span></span>
<span class="line" id="e326cb7L4"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb7L4"></a><span class="line-content">ln<span class="w"> </span>-s<span class="w"> </span>../static<span class="w"> </span>.</span></span>
</pre></figure><p>You will also probably want to create a <code>.htaccess</code> file under <code>public/</code> with the following contents:</p><figure class="blockcode"><pre class="highlight" data-language="htaccess" data-line-numbers><span class="line" id="e326cb8L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb8L1"></a><span class="line-content">RewriteCond %{REQUEST_FILENAME} !-f</span></span>
<span class="line" id="e326cb8L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb8L2"></a><span class="line-content">RewriteRule ^(.*\.php)$ /$1.PUBL_PATHALIAS [L]</span></span>
</pre></figure><h3 id="326_h3_5_Care-and-feeding"><a href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#326_h3_5_Care-and-feeding"></a>Care and feeding</h3><p>Upgrading Publ should just be a matter of <code>ssh</code>ing to your host, <code>cd</code>ing into the site directory, and running:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e326cb9L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb9L1"></a><span class="line-content">pipenv<span class="w"> </span>update</span></span>
</pre></figure><p>After doing this, or after changing any site templates, you&rsquo;ll want to restart your website.
On Dreamhost you do this with:</p><figure class="blockcode"><pre class="highlight" data-language="bash" data-line-numbers><span class="line" id="e326cb10L1"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb10L1"></a><span class="line-content"><span class="nb">cd</span><span class="w"> </span><span class="o">(</span>website_directory<span class="o">)</span></span></span>
<span class="line" id="e326cb10L2"><a class="line-number" href="https://publ.beesbuzz.biz/manual/deploying/326-Passenger#e326cb10L2"></a><span class="line-content">mkdir<span class="w"> </span>-p<span class="w"> </span>tmp<span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span>touch<span class="w"> </span>tmp/restart.txt</span></span>
</pre></figure>

]]>
        </content>
    </entry>
    

    
</feed>