309 lines
58 KiB
XML
309 lines
58 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
||
<?xml-stylesheet type="text/xsl" href="/simple-atom.xslt"?>
|
||
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US">
|
||
<title>joshua.seigler.net - how to</title>
|
||
<subtitle>Personal homepage of Joshua Seigler</subtitle>
|
||
<link href="https://joshua.seigler.net/feeds/how-to.xml" rel="self" />
|
||
<link href="https://joshua.seigler.net/" />
|
||
<updated>2025-06-28T00:00:00Z</updated>
|
||
<id>https://joshua.seigler.net/</id>
|
||
<author>
|
||
<name></name>
|
||
</author>
|
||
<entry>
|
||
<title>My Very Own GitHub Pages</title>
|
||
<link href="https://joshua.seigler.net/posts/my-very-own-github-pages/" />
|
||
<updated>2025-06-15T00:00:00Z</updated>
|
||
<id>https://joshua.seigler.net/posts/my-very-own-github-pages/</id>
|
||
<content type="html"><p>I recently started self-hosting <a href="https://forgejo.org/" target="_blank" rel="noopener">Forgejo</a>, but I wanted something to replace GitHub pages, which has been very convenient for publishing little website projects. My server runs Debian, so I decided to use <a href="https://github.com/adnanh/webhook" target="_blank" rel="noopener">webhook</a> and <a href="https://caddyserver.com/" target="_blank" rel="noopener">Caddy</a>. I’m very happy how it turned out.</p>
|
||
<h2 id="the-objective" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/my-very-own-github-pages/#the-objective" aria-hidden="true"></a> The objective</h2>
|
||
<p>When I push a <code>gh-pages</code> branch to any public repository on my Forgejo instance, the name of the repo is used as a domain name (e.g. <a href="https://marklink.pages.seigler.net/" target="_blank" rel="noopener">marklink.pages.seigler.net</a>) and the branch contents are automatically served with SSL. If I push updates to the branch, they are automatically published. If the branch or repo is deleted, the site is taken down.</p>
|
||
<h2 id="how-to-do-it" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/my-very-own-github-pages/#how-to-do-it" aria-hidden="true"></a> How to do it</h2>
|
||
<h3 id="debian-server-preparation" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/my-very-own-github-pages/#debian-server-preparation" aria-hidden="true"></a> Debian server preparation</h3>
|
||
<p>In case you don’t have a basic server setup routine yet, this is a good start:</p>
|
||
<ul>
|
||
<li>Change the default root password.</li>
|
||
<li>Create a new user and add it to the sudo group. In my examples below the user is <code>joshua</code>.</li>
|
||
<li>Use <code>ssh-copy-id</code> to install your ssl pubkey for easier login.</li>
|
||
<li>Disable/lock root’s password.</li>
|
||
<li>Disable root login over ssh and change the SSL port number. Pick a new port lower than 1024.</li>
|
||
<li>Edit your local <code>~/.ssh/config</code> so you don’t have to specify the port number every time you connect.</li>
|
||
<li>On the server, install and enable <code>ufw</code> and <code>fail2ban</code>. In addition to allowing your custom SSL port, be sure to enable ports 80 and 443 with <code>sudo ufw allow &quot;WWW Full&quot;</code>.</li>
|
||
</ul>
|
||
<h3 id="caddy" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/my-very-own-github-pages/#caddy" aria-hidden="true"></a> Caddy</h3>
|
||
<p>I usually use nginx, but I wanted to give Caddy a shot, and it has been a great experience. I installed Caddy using the <a href="https://caddyserver.com/docs/install" target="_blank" rel="noopener">official instructions</a>.<br>
|
||
Here is the Caddyfile I made—you will need to change the domain names and the email. Email could be removed, but it is there so that SSL certificate issuers can contact you if there is a problem with your certificates.</p>
|
||
<p><code>/etc/caddy/Caddyfile</code></p>
|
||
<pre class="language-caddy"><code class="language-caddy"><span class="highlight-line"># Global options block</span>
|
||
<span class="highlight-line">{</span>
|
||
<span class="highlight-line"> email you@example.com #### CHANGE THIS ####</span>
|
||
<span class="highlight-line"> on_demand_tls {</span>
|
||
<span class="highlight-line"> ask http://localhost/check</span>
|
||
<span class="highlight-line"> }</span>
|
||
<span class="highlight-line">}</span>
|
||
<span class="highlight-line"></span>
|
||
<span class="highlight-line"># Webhooks</span>
|
||
<span class="highlight-line">https://webhooks.subdomain.here.tld { #### CHANGE THIS ####</span>
|
||
<span class="highlight-line"> reverse_proxy localhost:9000</span>
|
||
<span class="highlight-line">}</span>
|
||
<span class="highlight-line"></span>
|
||
<span class="highlight-line"># Filter for which SSL certs we will create. Prevents abuse.</span>
|
||
<span class="highlight-line">http://localhost {</span>
|
||
<span class="highlight-line"> handle /check {</span>
|
||
<span class="highlight-line"> root * /var/www</span>
|
||
<span class="highlight-line"> @deny not file /{query.domain}/</span>
|
||
<span class="highlight-line"> respond @deny 404</span>
|
||
<span class="highlight-line"> }</span>
|
||
<span class="highlight-line">}</span>
|
||
<span class="highlight-line"></span>
|
||
<span class="highlight-line"># This automatically handles upgrading http:// requests with a redirect</span>
|
||
<span class="highlight-line">https:// {</span>
|
||
<span class="highlight-line"> tls {</span>
|
||
<span class="highlight-line"> on_demand</span>
|
||
<span class="highlight-line"> }</span>
|
||
<span class="highlight-line"> root /var/www</span>
|
||
<span class="highlight-line"> rewrite /{host}{uri}</span>
|
||
<span class="highlight-line"> @forbidden {</span>
|
||
<span class="highlight-line"> path /.*</span>
|
||
<span class="highlight-line"> }</span>
|
||
<span class="highlight-line"> respond @forbidden 404</span>
|
||
<span class="highlight-line"> file_server</span>
|
||
<span class="highlight-line">}</span>
|
||
<span class="highlight-line"></span>
|
||
<span class="highlight-line"># Refer to the Caddy docs for more information:</span>
|
||
<span class="highlight-line"># https://caddyserver.com/docs/caddyfile</span>
|
||
<span class="highlight-line"></span>
|
||
<span class="highlight-line"># This config based on information at</span>
|
||
<span class="highlight-line"># https://caddy.community/t/on-demand-tls-with-dynamic-content-paths/18140</span>
|
||
<span class="highlight-line"># checked and corrected with `caddy validate`</span></code></pre>
|
||
<p>I also took ownership of <code>/var/www</code> with <code>chown -R joshua:joshua /var/www</code> since the webhooks will run as my login account.</p>
|
||
<h3 id="webhooks" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/my-very-own-github-pages/#webhooks" aria-hidden="true"></a> Webhooks</h3>
|
||
<p>In my home directory I defined two hook scripts:</p>
|
||
<p><code>~/webhooks/update-pages.sh</code></p>
|
||
<pre class="language-bash"><code class="language-bash"><span class="highlight-line"><span class="token shebang important">#!/bin/bash</span></span>
|
||
<span class="highlight-line"><span class="token comment"># parameter 1 is repo name, parameter 2 is clone url</span></span>
|
||
<span class="highlight-line"><span class="token punctuation">[</span><span class="token punctuation">[</span> <span class="token string">"<span class="token variable">$1</span>"</span> <span class="token operator">==</span> *<span class="token string">"/"</span>* <span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">exit</span> <span class="token number">1</span><span class="token punctuation">;</span></span>
|
||
<span class="highlight-line"><span class="token punctuation">[</span><span class="token punctuation">[</span> <span class="token string">"<span class="token variable">$1</span>"</span> <span class="token operator">==</span> *<span class="token string">".."</span>* <span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">exit</span> <span class="token number">1</span><span class="token punctuation">;</span></span>
|
||
<span class="highlight-line"><span class="token punctuation">[</span><span class="token punctuation">[</span> <span class="token string">"<span class="token variable">$1</span>"</span> <span class="token operator">==</span> *<span class="token string">"*"</span>* <span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">exit</span> <span class="token number">1</span><span class="token punctuation">;</span></span>
|
||
<span class="highlight-line"><span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token parameter variable">-d</span> <span class="token string">"/var/www/<span class="token variable">$1</span>"</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span></span>
|
||
<span class="highlight-line"> <span class="token builtin class-name">cd</span> <span class="token string">"/var/www/<span class="token variable">$1</span>"</span><span class="token punctuation">;</span></span>
|
||
<span class="highlight-line"> <span class="token function">git</span> fetch origin gh-pages<span class="token punctuation">;</span></span>
|
||
<span class="highlight-line"> <span class="token function">git</span> reset <span class="token parameter variable">--hard</span> origin/gh-pages<span class="token punctuation">;</span></span>
|
||
<span class="highlight-line"> <span class="token builtin class-name">exit</span><span class="token punctuation">;</span></span>
|
||
<span class="highlight-line"><span class="token keyword">fi</span><span class="token punctuation">;</span></span>
|
||
<span class="highlight-line"><span class="token function">git</span> clone <span class="token parameter variable">-b</span> gh-pages --single-branch <span class="token string">"<span class="token variable">$2</span>"</span> <span class="token string">"<span class="token variable">$1</span>"</span> <span class="token operator">||</span> <span class="token builtin class-name">exit</span> <span class="token number">1</span><span class="token punctuation">;</span></span></code></pre>
|
||
<p><code>~/webhooks/remove-pages.sh</code></p>
|
||
<pre class="language-bash"><code class="language-bash"><span class="highlight-line"><span class="token shebang important">#!/bin/bash</span></span>
|
||
<span class="highlight-line"><span class="token comment"># parameter 1 is repo name</span></span>
|
||
<span class="highlight-line"><span class="token punctuation">[</span><span class="token punctuation">[</span> <span class="token string">"<span class="token variable">$1</span>"</span> <span class="token operator">==</span> *<span class="token string">"/"</span>* <span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">exit</span> <span class="token number">1</span><span class="token punctuation">;</span></span>
|
||
<span class="highlight-line"><span class="token punctuation">[</span><span class="token punctuation">[</span> <span class="token string">"<span class="token variable">$1</span>"</span> <span class="token operator">==</span> *<span class="token string">".."</span>* <span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">exit</span> <span class="token number">1</span><span class="token punctuation">;</span></span>
|
||
<span class="highlight-line"><span class="token punctuation">[</span><span class="token punctuation">[</span> <span class="token string">"<span class="token variable">$1</span>"</span> <span class="token operator">==</span> *<span class="token string">"*"</span>* <span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">exit</span> <span class="token number">1</span><span class="token punctuation">;</span></span>
|
||
<span class="highlight-line"><span class="token punctuation">[</span> <span class="token parameter variable">-d</span> <span class="token string">"/var/www/<span class="token variable">$1</span>"</span> <span class="token punctuation">]</span> <span class="token operator">||</span> <span class="token builtin class-name">exit</span> <span class="token number">1</span><span class="token punctuation">;</span></span>
|
||
<span class="highlight-line"><span class="token builtin class-name">cd</span> <span class="token string">"/var/www"</span><span class="token punctuation">;</span></span>
|
||
<span class="highlight-line"><span class="token function">rm</span> <span class="token parameter variable">-rf</span> <span class="token string">"/var/www/<span class="token variable">$1</span>"</span><span class="token punctuation">;</span></span></code></pre>
|
||
<p>To trigger these hooks I am using <code>webhook</code> which is in the default Debian repository.</p>
|
||
<p>Here are the hook definitions: one for creating/updating a site, and one for deleting. You will need to generate one or two secret values that the server can use to know that the webhook is authorized to run. I used linux command <code>uuidgen -r</code> to create mine. Save these values so you can enter them in Forgejo later.</p>
|
||
<p>Also make sure to replace your execute-command lines with ones referencing your username and script paths.</p>
|
||
<p><code>/etc/webhook.conf</code></p>
|
||
<pre class="language-json"><code class="language-json"><span class="highlight-line"><span class="token punctuation">[</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span></span>
|
||
<span class="highlight-line"> <span class="token property">"id"</span><span class="token operator">:</span> <span class="token string">"update-pages"</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token property">"execute-command"</span><span class="token operator">:</span> <span class="token string">"/usr/bin/sudo"</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token property">"pass-arguments-to-command"</span><span class="token operator">:</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">[</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span> <span class="token property">"source"</span><span class="token operator">:</span> <span class="token string">"string"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"-u"</span><span class="token punctuation">}</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span> <span class="token property">"source"</span><span class="token operator">:</span> <span class="token string">"string"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"joshua"</span><span class="token punctuation">}</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span> <span class="token property">"source"</span><span class="token operator">:</span> <span class="token string">"string"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"/home/joshua/webhooks/update-pages.sh"</span><span class="token punctuation">}</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span> <span class="token property">"source"</span><span class="token operator">:</span> <span class="token string">"payload"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"repository.name"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span> <span class="token property">"source"</span><span class="token operator">:</span> <span class="token string">"payload"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"repository.clone_url"</span> <span class="token punctuation">}</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token property">"trigger-rule"</span><span class="token operator">:</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span></span>
|
||
<span class="highlight-line"> <span class="token property">"and"</span><span class="token operator">:</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">[</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span></span>
|
||
<span class="highlight-line"> <span class="token property">"match"</span><span class="token operator">:</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span></span>
|
||
<span class="highlight-line"> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"payload-hmac-sha256"</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token property">"secret"</span><span class="token operator">:</span> <span class="token string">"(omitted)"</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token property">"parameter"</span><span class="token operator">:</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span></span>
|
||
<span class="highlight-line"> <span class="token property">"source"</span><span class="token operator">:</span> <span class="token string">"header"</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"X-Forgejo-Signature"</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">}</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">}</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">}</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span></span>
|
||
<span class="highlight-line"> <span class="token property">"match"</span><span class="token operator">:</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span></span>
|
||
<span class="highlight-line"> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"value"</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"refs/heads/gh-pages"</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token property">"parameter"</span><span class="token operator">:</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span></span>
|
||
<span class="highlight-line"> <span class="token property">"source"</span><span class="token operator">:</span> <span class="token string">"payload"</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"ref"</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">}</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">}</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">}</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">]</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">}</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">}</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span></span>
|
||
<span class="highlight-line"> <span class="token property">"id"</span><span class="token operator">:</span> <span class="token string">"remove-pages"</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token property">"execute-command"</span><span class="token operator">:</span> <span class="token string">"/usr/bin/sudo"</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token property">"pass-arguments-to-command"</span><span class="token operator">:</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">[</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span> <span class="token property">"source"</span><span class="token operator">:</span> <span class="token string">"string"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"-u"</span><span class="token punctuation">}</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span> <span class="token property">"source"</span><span class="token operator">:</span> <span class="token string">"string"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"joshua"</span><span class="token punctuation">}</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span> <span class="token property">"source"</span><span class="token operator">:</span> <span class="token string">"string"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"/home/joshua/webhooks/remove-pages.sh"</span><span class="token punctuation">}</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span> <span class="token property">"source"</span><span class="token operator">:</span> <span class="token string">"payload"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"repository.name"</span> <span class="token punctuation">}</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token property">"trigger-rule"</span><span class="token operator">:</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span></span>
|
||
<span class="highlight-line"> <span class="token property">"and"</span><span class="token operator">:</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">[</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span></span>
|
||
<span class="highlight-line"> <span class="token property">"match"</span><span class="token operator">:</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span></span>
|
||
<span class="highlight-line"> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"payload-hmac-sha256"</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token property">"secret"</span><span class="token operator">:</span> <span class="token string">"(omitted)"</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token property">"parameter"</span><span class="token operator">:</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">{</span></span>
|
||
<span class="highlight-line"> <span class="token property">"source"</span><span class="token operator">:</span> <span class="token string">"header"</span><span class="token punctuation">,</span></span>
|
||
<span class="highlight-line"> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"X-Forgejo-Signature"</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">}</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">}</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">}</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">]</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">}</span></span>
|
||
<span class="highlight-line"> <span class="token punctuation">}</span></span>
|
||
<span class="highlight-line"><span class="token punctuation">]</span></span></code></pre>
|
||
<h3 id="forgejo" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/my-very-own-github-pages/#forgejo" aria-hidden="true"></a> Forgejo</h3>
|
||
<p>Forgejo supports running webhooks conditionally triggered by certain conditions.<br>
|
||
Under my main user settings I set up each webhook:</p>
|
||
<h4 id="update-pages" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/my-very-own-github-pages/#update-pages" aria-hidden="true"></a> Update pages</h4>
|
||
<p>Target URL: https:// <em>your domain here</em> /hooks/update-pages<br>
|
||
HTTP Method: <code>POST</code> (the default)<br>
|
||
POST content type: <code>application/json</code> (the default)<br>
|
||
Secret: <em>omitted, use your own</em><br>
|
||
Trigger on: Push events<br>
|
||
Branch filter: <code>gh-pages</code></p>
|
||
<h4 id="remove-pages" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/my-very-own-github-pages/#remove-pages" aria-hidden="true"></a> Remove pages</h4>
|
||
<p>Target URL: https:// <em>your domain here</em> /hooks/remove-pages<br>
|
||
HTTP Method: <code>POST</code> (the default)<br>
|
||
POST content type: <code>application/json</code> (the default)<br>
|
||
Secret: <em>omitted, use your own</em><br>
|
||
Trigger on: Custom Events &gt; Repository &gt; Delete<br>
|
||
Branch filter: <code>gh-pages</code></p>
|
||
<h2 id="conclusion" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/my-very-own-github-pages/#conclusion" aria-hidden="true"></a> Conclusion</h2>
|
||
<p>It works!<br>
|
||
Here is <a href="https://git.apps.seigler.net/joshua/marklink.pages.seigler.net" target="_blank" rel="noopener">the marklink repo in my Forgejo instance</a> and <a href="https://marklink.pages.seigler.net/" target="_blank" rel="noopener">its contents on my Caddy server</a>.</p>
|
||
<p>That repo is just HTML and JS with only a gh-pages branch, but for repos with npm build scripts, I use <a href="https://www.npmjs.com/package/gh-pages" target="_blank" rel="noopener">gh-pages @ npm</a> to push the build to a gh-pages branch and up to the server.</p>
|
||
<p>I’m putting off rolling my own CI server, but I imagine that’s the next stage here. Stay tuned.</p>
|
||
</content>
|
||
</entry>
|
||
<entry>
|
||
<title>Needs-based communication</title>
|
||
<link href="https://joshua.seigler.net/posts/needs-based-communication/" />
|
||
<updated>2021-05-26T00:00:00Z</updated>
|
||
<id>https://joshua.seigler.net/posts/needs-based-communication/</id>
|
||
<content type="html"><p>Needs-based communication (usually called non-violent communication or NVC™) is a way of understanding yourself and others with a unique insight: everyone has their own personal reactions to the world, but people have the same basic needs. We recognize those needs in other people, and that common connection can allow us to communicate clearly when there is conflict.</p>
|
||
<h2 id="needs" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/needs-based-communication/#needs" aria-hidden="true"></a> Needs</h2>
|
||
<p><strong>Needs</strong> are universal to humanity. They are common drives that we all experience, and this universality makes them perfect for connecting with each other. Some broad categories of needs are the needs for: connection, physical well-being, honesty, play, peace, autonomy, and meaning. Needs can also be specific: a need for clarity, nurturing, integrity, trust, space, etc. Needs are abstract, not connected to people or actions. For example, peace is a need, muting TV commercials is not. Here is an abbreviated list of needs from the Center for Non-Violent Communication (CNVC):</p>
|
||
<p><strong>Physical wellbeing</strong> - air, food, movement/exercise, rest/sleep, sexual expression, safety, shelter, touch, water<br>
|
||
<strong>Honesty</strong> - authenticity, integrity, presence<br>
|
||
<strong>Connection</strong> - acceptance, affection, appreciation, belonging, cooperation, communication, closeness, community, companionship, compassion, consideration, consistency, empathy, inclusion, intimacy, love, mutuality, nurturing, respect/self-respect, safety, security, stability, support, to know and be known, to see and be seen, to understand and be understood, trust, warmth<br>
|
||
<strong>Play</strong> - joy, humor<br>
|
||
<strong>Peace</strong> - beauty, communion, ease, equality, harmony, inspiration, order<br>
|
||
<strong>Autonomy</strong> - choice, freedom, independence, space, spontaneity<br>
|
||
<strong>Meaning</strong> - awareness, celebration of, life challenge, clarity, competence, consciousness, contribution, creativity, discovery, efficacy, effectiveness, growth, hope, learning, mourning, participation, purpose, self-expression, stimulation, to matter, understanding</p>
|
||
<p>Everything <em>anyone</em> does is an attempt to meet a need. None of these universal needs is wrong or inherently harmful, although sometimes the strategies we use can be.</p>
|
||
<h2 id="conflict" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/needs-based-communication/#conflict" aria-hidden="true"></a> Conflict</h2>
|
||
<p><strong>Conflict</strong> happens when several peoples’ needs aren’t met. We get stuck in conflict when we mix up needs and strategies. Needs never conflict with each other, only strategies do.</p>
|
||
<p>When we experience conflict or negative feelings, that indicates that there is an unmet need. In an attempt to end a conflict, we often settle on unsatisfying resolutions:</p>
|
||
<ol>
|
||
<li>We suppress the need and move on, painfully leaving the problem unaddressed.</li>
|
||
<li>We come to an uneasy agreement about who is the winner and who is the loser, and the loser gives up on meeting their need. The immediate conflict is over, but the problem is not really resolved.</li>
|
||
<li>We escalate, expanding the conflict in an attempt to win, at the other’s expense if necessary.</li>
|
||
</ol>
|
||
<p>These resolutions can happen despite our best intentions, as a result of not understanding what’s happening as we fight. A very common mistake is to confuse needs and strategies.</p>
|
||
<h2 id="strategies" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/needs-based-communication/#strategies" aria-hidden="true"></a> Strategies</h2>
|
||
<p><strong>Strategies</strong> are things we do to meet our needs. In contrast to needs, which are abstract and universal, strategies are personal, specific, and widely varied.</p>
|
||
<p>For example, consider the need for self-expression. There are as many strategies as there are people and situations: singing, writing, talking, composing, dressing a certain way… and on and on.</p>
|
||
<p>Jumping into a conflict strategy-first is bound to cause problems if that strategy doesn’t meet others’ needs as well as your own. The way past conflict is for everyone involved to understand each others’ needs, and <em>then</em> work together to find a strategy to meet those needs.</p>
|
||
<p>So, <strong>how do you figure out your own needs?</strong></p>
|
||
<h2 id="feelings" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/needs-based-communication/#feelings" aria-hidden="true"></a> Feelings</h2>
|
||
<p>Negative feelings are a sign that you have an unmet need. Unfortunately, most of us have learned to bundle in certain judgments and name them as feelings. For example, I might think I am feeling <em>abandoned</em>, but really this is a feeling of disconnectedness, vulnerability, loneliness, or something else, combined with a judgment that someone else has made me feel that way.</p>
|
||
<p>The truth is that the same situation can affect different people in very different ways. This means that feelings must come from a person’s own response to things. In order to see your own feelings clearly, it is important to take ownership of them as <em>your</em> feelings rather than something caused by the world around you. I have found this to be very challenging, but also incredibly rewarding.</p>
|
||
<p>CNVC provides an incomplete inventory of feelings:</p>
|
||
<h3 id="feelings-when-needs-are-met" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/needs-based-communication/#feelings-when-needs-are-met" aria-hidden="true"></a> Feelings when needs are met</h3>
|
||
<p><strong>Affectionate</strong> - compassionate, friendly, loving, open-hearted, sympathetic, tender, warm<br>
|
||
<strong>Engaged</strong> - absorbed, alert, curious, engrossed, enchanted, entranced, fascinated, interested, intrigued, involved, spellbound, stimulated<br>
|
||
<strong>Hopeful</strong> - expectant, encouraged, optimistic<br>
|
||
<strong>Confident</strong> - empowered, open, proud, safe, secure<br>
|
||
<strong>Excited</strong> - amazed, animated, ardent, aroused, astonished, dazzled, eager, energetic, enthusiastic, giddy, invigorated, lively, passionate, surprised, vibrant<br>
|
||
<strong>Grateful</strong> - appreciative, moved, thankful, touched<br>
|
||
<strong>Inspired</strong> - amazed, awed, wonder<br>
|
||
<strong>Refreshed</strong> - enlivened, rejuvenated, renewed, rested, restored, revived</p>
|
||
<h3 id="feelings-when-needs-are-not-met" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/needs-based-communication/#feelings-when-needs-are-not-met" aria-hidden="true"></a> Feelings when needs are not met</h3>
|
||
<p><strong>Afraid</strong> - apprehensive, dread, foreboding, frightened, mistrustful, panicked, petrified, scared, suspicious, terrified, wary, worried<br>
|
||
<strong>Annoyed</strong> - aggravated, dismayed, disgruntled, displeased, exasperated, frustrated, impatient, irritated, irked<br>
|
||
<strong>Angry</strong> - enraged, furious, incensed, indignant, irate, livid, outraged, resentful<br>
|
||
<strong>Aversion</strong> - animosity, appalled, contempt, disgusted, dislike, hate, horrified, hostile, repulsed<br>
|
||
<strong>Confused</strong> - ambivalent, baffled, bewildered, dazed, hesitant, lost, mystified, perplexed, puzzled, torn<br>
|
||
<strong>Disconnected</strong> - alienated, aloof, apathetic, bored, cold, detached, distant, distracted, indifferent, numb, removed, uninterested, withdrawn<br>
|
||
<strong>Disquiet</strong> - agitated, alarmed, discombobulated, disconcerted, disturbed, perturbed, rattled, restless, shocked, startled, surprised, troubled, turbulent, turmoil, uncomfortable, uneasy, unnerved, unsettled, upset<br>
|
||
<strong>Embarrassed</strong> - ashamed, chagrined, flustered, guilty, mortified, self-conscious<br>
|
||
<strong>Fatigue</strong> - beat, burnt out, depleted, exhausted, lethargic, listless, sleepy, tired, weary, worn out<br>
|
||
<strong>Pain</strong> - agony, anguished, bereaved, devastated, grief, heartbroken, hurt, lonely, miserable, regretful, remorseful<br>
|
||
<strong>Sad</strong> - depressed, dejected, despair, despondent, disappointed, discouraged, disheartened, forlorn, gloomy, heavy-hearted, hopeless, melancholy, unhappy, wretched<br>
|
||
<strong>Tense</strong> - anxious, cranky, distressed, distraught, edgy, fidgety, frazzled, irritable, jittery nervous, overwhelmed, restless, stressed out<br>
|
||
<strong>Vulnerable</strong> - fragile, guarded, helpless, insecure, leery, reserved, sensitive, shaky<br>
|
||
<strong>Yearning</strong> - envious, jealous, longing, nostalgic, pining, wistful</p>
|
||
<h2 id="resolving-feelings-from-unmet-needs" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/needs-based-communication/#resolving-feelings-from-unmet-needs" aria-hidden="true"></a> Resolving feelings from unmet needs</h2>
|
||
<p>Once you have an honest name for what you are feeling, think about what need sparked the feeling.</p>
|
||
<p>There is a (kind of clunky) formula for requesting help meeting a need without tacking on strategies, demands, judgments, or other baggage. As the exercise becomes more habitual, you won’t need the formula, and can accomplish the same thing more naturally.</p>
|
||
<p>Here it is:</p>
|
||
<blockquote>
|
||
<p>When <em>[observation]</em>, I felt <em>[feeling]</em> because I was having a need for <em>[need]</em>. (possibly also a request:) Are you willing to <em>[action]</em>?</p>
|
||
</blockquote>
|
||
<p>In the spirit of communicating without judgments, the observation should be strictly focused on facts, with no mind-reading or attribution at all. Sharing your feelings in addition to the need can help the other person recognize the need and how it affects you. If the other person understands the need, you can also make a request for some specific action to help meet your need.</p>
|
||
<p>It is very important that the action you request be feasible, concrete, and specific. Asking someone to change their behavior forever, think a certain way, etc is too much. The request should also really, truly be a request and not a demand. A “No!” should be as welcome as a “Yes!” because the goal is to find a strategy that meets your needs <em>and</em> theirs.</p>
|
||
<p>There is a (similarly clunky) pattern for discovering someone else’s needs. As you listen to them, you will probably get an idea for how they feel, and you may be able to guess what need they are experiencing. You can ask:</p>
|
||
<blockquote>
|
||
<p>When you <em>[observation]</em> do you feel <em>[feeling]</em> because you are having a need for <em>[need]</em>? (possibly also:) Right now, would you like me to <em>[action]</em>?</p>
|
||
</blockquote>
|
||
<p>Like the other formula, this is just a beginning point, almost too rough to use except for training your responses and replacing old communication habits.</p>
|
||
<p>These are two sides of the same coin, a pattern that draws a line from the stimulus, some observation, through the needs, towards a solution. Even if you guess wrong, just focusing on someone’s feelings and needs demonstrates that you are really interested in their problem.</p>
|
||
<p>Even without explicitly using this pattern (observation ➔ feeling ➔ need ➔ request), just by thinking about needs (your own and others’) you can untangle conflict and see other people with much more empathy. Maybe that reckless driver is having a need for excitement and power, and zipping around you was the best strategy they could come up with. Just seeing past the image of others as enemies or obstacles can make the world much less hostile, by revealing them to be real humans, people you might be able to connect with. This way of thinking can also be a path to growth as you take ownership of your feelings and see your needs clearly.</p>
|
||
<p>Some resources for exploring these ideas more:</p>
|
||
<ul>
|
||
<li><a href="http://www.therightword.info/" target="_blank" rel="noopener">The Right Words and Beyond</a></li>
|
||
<li><a href="https://amzn.to/44cpIsV" target="_blank" rel="noopener">Nonviolent Communication: A Language of Life</a>, ISBN 189200528X</li>
|
||
<li><a href="https://www.cnvc.org/" target="_blank" rel="noopener">The Center for Nonviolent Communication</a></li>
|
||
</ul>
|
||
</content>
|
||
</entry>
|
||
<entry>
|
||
<title>The Trivium: A Tool for Learning Anything</title>
|
||
<link href="https://joshua.seigler.net/posts/the-trivium-a-tool-for-learning-anything/" />
|
||
<updated>2021-04-03T00:00:00Z</updated>
|
||
<id>https://joshua.seigler.net/posts/the-trivium-a-tool-for-learning-anything/</id>
|
||
<content type="html"><p>Information today has become siloed. It’s a common belief that little, if any, expertise from one field of knowledge transfers over to other fields. But there is a forgotten tool that anyone can use to confidently approach new subjects and problems: the <em>Trivium</em>.</p>
|
||
<p>The ancients considered the liberal arts to be composed of seven parts. First was a foundation called the <em>trivium</em>, composed of grammar, logic, and rhetoric. Following that was the <em>quadrivium</em>, which was arithmetic, geometry, music, and astronomy (numbers, numbers in space, numbers in time, numbers in time and space). The trivium (literally, “three ways”), is a framework for learning.</p>
|
||
<h2 id="grammar" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/the-trivium-a-tool-for-learning-anything/#grammar" aria-hidden="true"></a> Grammar</h2>
|
||
<p>Grammar is about gaining knowledge: collecting information, without judgment or analysis. It answers the questions “Who, what, where, and when?” This is possibly the most important step, since (depending on what you study) essential information may not be readily available.</p>
|
||
<h2 id="logic" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/the-trivium-a-tool-for-learning-anything/#logic" aria-hidden="true"></a> Logic</h2>
|
||
<p>Logic is about gaining understanding. It answers “why?” This is the foundation for relating to the world. It has three components: filtration, correlation, and analysis. It places the information gathered into context, and eliminates inconsistency and resolves conflicting perspectives.</p>
|
||
<h2 id="rhetoric" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/the-trivium-a-tool-for-learning-anything/#rhetoric" aria-hidden="true"></a> Rhetoric</h2>
|
||
<p>Rhetoric is about acting wisely: the application of knowledge and understanding, put into correct action. It answers “how?”</p>
|
||
<p>Methodically applying this method provides a clear next step when encountering any unfamiliar topic. This is a powerful tool for methodically determining the best way to achieve your goals.</p>
|
||
<h2 id="resources" tabindex="-1"><a class="header-anchor" href="https://joshua.seigler.net/posts/the-trivium-a-tool-for-learning-anything/#resources" aria-hidden="true"></a> Resources</h2>
|
||
<ul>
|
||
<li><a href="https://triviumbinder.blogspot.com/" target="_blank" rel="noopener">Trivium Binder Project</a></li>
|
||
<li><a href="http://www.scribd.com/doc/59477946/Trivium-Method-of-Critical-Thinking-and-Creative-Problem-Solving" target="_blank" rel="noopener">Tragedy and Hope: Five page summary of the Trivium</a></li>
|
||
<li><a href="https://www.scribd.com/document/33744483/Trivium-Method-of-Thinking-vs-Other-Methodologies" target="_blank" rel="noopener">Shadows of the trivium in narrow disciplines</a></li>
|
||
</ul>
|
||
</content>
|
||
</entry>
|
||
</feed>
|