pull in old static files
All checks were successful
/ build (push) Successful in 46s

This commit is contained in:
Nycki 2025-08-21 18:39:02 -07:00
parent 5c5cbfe9a3
commit 14c5d7d61c
15 changed files with 771 additions and 0 deletions

BIN
static/2007/Images/Gami.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

23
static/2007/cartoons.html Normal file
View file

@ -0,0 +1,23 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Traps and Zoids</title>
</head>
<body bgcolor=#36c1fc>
<h1><center>Cartoons!</center></h1>
<br><b>Traps and Zoids</b>
<br><a href="trapzoid01.html">1-Supply and demand</a>
<br><a href="trapzoid02.html">2-Metajoke</a>
<br><a href="trapzoid03.html">3-A Trail of Pens</a>
<br><hr color="orange">
<br>More to come...
<br>eventually...
<!--, check back in a couple weeks or so!-->
<br><a href="index.html"><font color="red" size="4">Back</font></a>
</body>
</html>

41
static/2007/index.html Normal file
View file

@ -0,0 +1,41 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Nick.lamicela.org</title>
</head>
<body bgcolor=#36c1fc>
<center><h4><font color="red">
Welcome to Nick.Lamicela.Org!
</font></h></center>
<center><table><tr><td><center>
<!-- News Page Image -->
<img src="Images/NewsCompass.gif" width="300" height="297" alt="News" border="0">
</center></td><td><center>
<!-- Cartoons page image -->
<img src="Images/Gami.gif" width="280" height="235" alt="" border="0">
</center></td></tr><tr><td><center>
<!-- News Page Link -->
<br><a href="news.html"><font color="green" size="6">News</font></a>
</center></td><td><center>
<!-- Cartoons Page Link -->
<br><a href="cartoons.html"><font color="green" size="6">Cartoons</font></a>
</center></td></tr></table><br>
<!-- Last Updated Date -->
<center><table><tr><td bgcolor="black"><font face="fixedsys, courier new, courier" size="5" color="green">
Last updated: 08/01/07
</font></td></tr></table></center>
</body>
</html>

11
static/2007/news.html Normal file
View file

@ -0,0 +1,11 @@
<html>
<head>
<title>What's up?</title>
</head
<body bgcolor=#36c1fc>
<font color="red"><i>08/01/2007:</i></font> I guess what's new today is that I ummm, have a news page? I had an idea for the logo in the middle of the night last night and I got out of bed, drew the compass thingy, inked it, and went back to bed. This morning I colored it in photoshop and added it to my website, along with this news page. If I ever update again, You'll know about it here.
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>01-Supply and Demand</title>
</head>
<body bgcolor=#36c1fc>
<center>
<h5>Episode 1-supply and demand.</h>
<br><img src="Images/Traps_and_zoids01.gif" width="600" height="200" alt="" border="0">
<br><a href="cartoons.html">back</a>
</center>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>02-Metajoke</title>
</head>
<body bgcolor=#36c1fc>
<center>
<h5>Episode 2-Metajoke</h>
<br><img src="Images/Traps_and_zoids02.gif">
<br><a href="cartoons.html">back</a>
</center>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>03-A Trail of Pens...</title>
</head>
<body bgcolor=#36c1fc>
<center>
<h5>Episode 3-A Trail of Pens</h>
<br><img src="Images/Traps_and_zoids03.gif">
<br><a href="cartoons.html">back</a>
</center>
</body>
</html>

448
static/cookbook/index.html Normal file
View file

@ -0,0 +1,448 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>nyckis simple cookbook for Linux, v0.10.2</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
</style>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<nav>
<a href="/">home</a>
</nav>
<header id="title-block-header">
<h1 class="title">nyckis simple cookbook for Linux, <a href="https://github.com/nycki93/cookbook">v0.10.2</a></h1>
</header>
<nav id="TOC" role="doc-toc">
<ul>
<li><a href="#introduction">introduction</a>
<ul>
<li><a href="#why-a-cookbook">why a cookbook?</a></li>
<li><a href="#why-all-the-lowercase">why all the lowercase?</a></li>
<li><a href="#who-is-your-audience">who is your audience?</a></li>
</ul></li>
<li><a href="#materials">materials</a></li>
<li><a href="#usernames-and-passwords">usernames and passwords</a></li>
<li><a href="#operating-system">operating system</a></li>
<li><a href="#format-storage">format storage</a></li>
<li><a href="#mount-storage">mount storage</a></li>
<li><a href="#backups">backups</a></li>
<li><a href="#website">website</a></li>
<li><a href="#networking">networking</a>
<ul>
<li><a href="#firewall">firewall</a></li>
<li><a href="#private-key-auth">private key auth</a></li>
<li><a href="#port-forwarding">port forwarding</a></li>
<li><a href="#https">https</a></li>
</ul></li>
<li><a href="#file-sharing">file sharing</a>
<ul>
<li><a href="#sync">sync</a></li>
</ul></li>
<li><a href="#containers">containers</a></li>
<li><a href="#database">database</a></li>
<li><a href="#apps">apps</a></li>
<li><a href="#auth">auth</a></li>
</ul>
</nav>
<section id="introduction" class="level2">
<h2>introduction</h2>
<section id="why-a-cookbook" class="level3">
<h3>why a cookbook?</h3>
<p>theres an old <a href="https://reddit.com/r/geek/comments/4zl3e1/happy_birthday_linux_heres_your_cake">joke</a> that using Linux is like ordering a cake and receiving a bunch of flour, sugar, butter, and eggs. many self-hosting tutorials read like the back of a box of cake mix, which is great if you want a cake fast, but unsatisfying if you want to learn about cake making. my goal is for this guide to teach you enough to improvise, to make substitutions.</p>
</section>
<section id="why-all-the-lowercase" class="level3">
<h3>why all the lowercase?</h3>
<p>a few people have asked me this. honestly I have some <a href="https://seximal.net">influences</a> but the main reason is that it reminds me of writing code. in code, uppercase letters are almost always reserved for names. I did my best to capitalize all names in this document the way their owners capitalize them, so the web protocol is HTTP, but the comic strip is xkcd.</p>
</section>
<section id="who-is-your-audience" class="level3">
<h3>who is your audience?</h3>
<p>this guide is for you if:</p>
<ul>
<li>youre me, and you forgot how you did this last time.</li>
<li>you want to share pictures and videos and dont want to use a commercial file host.</li>
<li>you want to run a communal server, like <a href="https://tilde.club">tilde.club</a>.</li>
<li>youre just curious about Linux and servers!</li>
</ul>
<p>sound good? then lets get cooking.</p>
</section>
</section>
<section id="materials" class="level2">
<h2>materials</h2>
<p>Ill be using a <a href="https://www.raspberrypi.com">Raspberry Pi 4b</a> and installing <a href="https://www.raspberrypi.com/software">Raspberry Pi OS</a> Lite (64-bit). its also known as Raspbian, since its based on <a href="https://www.debian.org/doc">Debian</a> Linux. any Debian-like OS will work for this tutorial. if the Raspberry Pi isnt available where and when you are, some good alternatives are the <a href="https://libre.computer/products/roc-rk3328-cc">Renegade</a> or the <a href="https://www.pine64.org/devices/single-board-computers/rock64">ROCK64</a>. If Raspbian doesnt run on your device, try <a href="https://www.armbian.com">armbian</a>.</p>
<p>youll also need a MicroSD card, a hard drive, and a second hard drive for backup. I recommend a 64GB MicroSD card and two 2TB hard drives. the Pi can power one hard drive via USB, but if you want to plug both in at once youll need a powered hard drive enclosure or a powered USB hub.</p>
<p>you can also adapt these directions to existing hardware you may already own, like an old laptop or desktop pc. you can also rent a virtual machine from a remote datacenter! the cheapest virtual machine on <a href="https://www.digitalocean.com">DigitalOcean</a> right now (as of 2023 July) costs 6 USD per month, and comes with 25GB of storage. renting a machine in a datacenter means you get the perks of high-speed internet all day and night, which is great if you are running a game server and need a fast connection. however, youll pay 10 USD per month for each 100GB of additional storage, so its not great if you want to host a huge media archive.</p>
<!-- todo: what about S3-compatible storage? -->
</section>
<section id="usernames-and-passwords" class="level2">
<h2>usernames and passwords</h2>
<p>at some point youll probably want to make your server available on the internet. there are bots out there that do nothing but guess random usernames and passwords all day, and they <em>will</em> find you, so you need to be prepared.</p>
<p>for your username, pick something short and catchy. in my experience, a typical linux username is from 3 to 8 characters long. if you have a short name like alice or bob you can use that. if you have a nickname online like azure or luna then that works too. if you have a middle name, you can use your initials, like jfk. your username should be all lowercase.</p>
<p>for your password, the most important factor is length. maybe youve been told that you need to add weird symbols and stuff in it, but that rule is for more limited systems. its the 64-bit era, baby! the only thing that matters is how much entropy your password has. <strong>entropy</strong> is basically a measure of how unlikely something is to happen by accident. like if I flip ten coins and you flip ten coins and we get the same sequence, the odds of that happening are 1 in 2^10, so we say that that particular sequence of flips has 10 bits of entropy. its recommended that your password have about 60 to 80 bits of entropy. yikes, thats a lot of coin flips to memorize!</p>
<p>luckily theres a better way. using a tool like <a href="https://xkpasswd.net/s/">xkpasswd</a> or <a href="https://theworld.com/~reinhold/diceware.html">diceware</a>, you can convert randomness into words. using the diceware list, you can roll 25 six-sided dice to get a random 25-digit sequence, and then convert each 5 digits into a word, to get a 5-word phrase. the odds of two people getting the same 5-word phrase are 1 in 6^25, which is approximately equal to 2^64, so this password has 64 bits of entropy. thats enough to make most hackers give up and move onto an easier target. go generate a password now, and save it somewhere safe, like a password manager program, or a piece of paper tucked inside a book. dont be afraid to write things down; sometimes paper is safer.</p>
</section>
<section id="operating-system" class="level2">
<h2>operating system</h2>
<p>time to download and install your operating system. there are lots of guides on how to install Linux already, <a href="https://www.raspberrypi.com/documentation/computers/getting-started.html">heres</a> one for Raspbian. Ill be using Raspberry Pi OS Lite (64-Bit), with the default settings. with these settings, there is no remote login available; you will need to plug a keyboard and monitor directly into the pi. on the first boot, youll be prompted to enter the username and password for the initial user. after that, youll be given a login prompt. log in with the username and password you just set. some operating systems display nothing at a password prompt, not even stars. once you log in, youll see some system information, and then a prompt that looks like this:</p>
<pre><code>user@raspberrypi:~ $</code></pre>
<p>this is a <strong>CLI</strong>, a command line interface. from left to right, this contains</p>
<ul>
<li>your name.</li>
<li>the machines name.</li>
<li>your current directory. <code>~</code> means “home”, and is short for <code>/home/user</code>.</li>
<li>a command prompt. this will be <code>$</code> if you are in user mode, or <code>#</code> if you are in admin mode.</li>
</ul>
<p>if youve ever used a bot in a chatroom, you already know how to use a command line interface! its a system where you type an instruction, and the computer answers you. here are some examples of commands you can type:</p>
<ul>
<li><code>whoami</code>: ask the computer what your name is.</li>
<li><code>hostname</code>: ask the computer what <em>its</em> name is.</li>
<li><code>pwd</code>: ask the computer where you are.</li>
<li><code>ls</code>: look at the files in your current location.</li>
<li><code>cd &lt;somewhere&gt;</code>: go somewhere else.</li>
<li><code>echo &lt;something&gt;</code>: ask the computer to repeat something back to you.</li>
<li><code>nano &lt;filename&gt;</code>: edit a text file.</li>
<li><code>cat &lt;filename&gt;</code>: print a text file to the screen.</li>
</ul>
<p>if this is your first time using a command line interface, try some of these commands now. use <code>nano myfile.txt</code> to open a text file, write some text to it, then save with ctrl-o, and exit with ctrl-x. use <code>ls</code> to look at that file, then use <code>cat myfile.txt</code> to have the computer read it back to you. pat yourself on the back, youre learning so much!</p>
<p>soon well unplug the keyboard and monitor from this computer, making it a headless server. before we can do that we need to run a few commands as administrator, or root. well do this with a very powerful command called <code>sudo</code>. sudo stands for super user do, and it means do the next thing as an administrator. you can use <code>sudo &lt;command&gt;</code> for a single command, or enter interactive mode with <code>sudo -i</code>. in interactive mode, <em>all</em> your commands will be admin commands, until you say <code>exit</code>.</p>
<p><span class="emoji" data-emoji="warning">⚠️</span> <strong>there is no undo button! if you say something with sudo, make sure you mean it!</strong></p>
<p>throughout this guide, Ill be using <code>$</code> at the start of a command if you run it as a normal user, or <code>#</code> if you run it as admin. either way, you dont actually type this symbol yourself, it should already appear on your command line.</p>
<p>well need to do these things before we can go headless:</p>
<ul>
<li>change <code>sudo</code> to require a password</li>
<li>change the hostname from the default</li>
<li>connect to a network</li>
<li>enable remote login</li>
<li>install operating system updates</li>
<li>reboot</li>
</ul>
<p>first well change the sudo rules for our account. there should be a config file at <code>/etc/sudoers.d/010_pi-nopasswd</code>. well use the special <code>visudo</code> command to edit it, which should launch <code>nano</code> like before, but with special safety guards to catch us if we lock ourselves out of administrator mode.</p>
<pre><code>$ sudo visudo /etc/sudoers.d/010_pi-nopasswd</code></pre>
<p>you should see a single line, like</p>
<pre><code>user ALL=(ALL) NOPASSWD: ALL</code></pre>
<p>remove the <code>NOPASSWD:</code> instruction, so this file reads</p>
<pre><code>user ALL=(ALL) ALL</code></pre>
<p>save and quit. from now on, if you havent used <code>sudo</code> in a few minutes, the system will ask for your password. this way if you accidentally leave yourself logged in, and someone else takes over your session, they wont automatically get sudo access.</p>
<p>we can do the next few steps with the <code>raspi-config</code> tool.</p>
<pre><code>$ sudo raspi-config</code></pre>
<p>the hostname is under System Options -&gt; Hostname. I set mine to teapot.</p>
<p>if your machine is plugged directly into your home router with a patch cable, you already have network access, otherwise set up wireless with System Options -&gt; Wireless LAN.</p>
<p>to enable remote login, go to Interface Options -&gt; SSH.</p>
<p>select Finish. youll be prompted to reboot, but dont yet, well reboot later after installing some updates. in Debian Linux, we update packages using a tool called <code>apt</code>. <code>apt update</code> checks for updated packages, and <code>apt upgrade</code> installs them. run both these commands now, using the interactive version of <code>sudo</code>.</p>
<pre><code>$ sudo -i
# apt update
# apt upgrade</code></pre>
<p>finally, if youre on a Raspberry Pi, then <code>avahi-daemon</code> is installed automatically. if not, you may need to install it yourself. this program broadcasts your hostname to the network, so you can log in remotely without configuring your router.</p>
<pre><code># apt install avahi-daemon</code></pre>
<p>now go ahead and reboot, to make sure your new hostname is in use.</p>
<pre><code># reboot</code></pre>
<p>after a minute, you should now be able to log in remotely from another computer, using</p>
<pre><code>$ ssh user@teapot</code></pre>
<p>if this works, congrats! you can now unplug the keyboard and monitor. youve created a headless server.</p>
</section>
<section id="format-storage" class="level2">
<h2>format storage</h2>
<p>the Raspberry Pi uses a MicroSD card as the operating system disk. its convenient; if the OS breaks you can just pull its brain out, factory reset it, and pop it back in. however, I dont want to store all my user data on that brain card. I think its better if you have a secondary disk that contains <em>only</em> the stuff you create yourself. that way if something goes wrong and you have to reset the brain card, you dont lose any of your personal data.</p>
<p>there are different formats for a data disk. the format determines exactly where the data and metadata will appear in each chunk of the disk. Windows typically uses <a href="https://en.wikipedia.org/wiki/NTFS">NTFS</a>, which supports metadata for ownership and last modified time, but not for fine-grained access like whether a file is shared with guests. Linux uses a format that does allow this fine-grained access, called <a href="https://en.wikipedia.org/wiki/Ext4">ext4</a>, so thats what we need to format the data disk as.</p>
<p>first we need to identify the disks device file. in Linux, everything you can read or write to is treated as a file, including a USB device like an external disk. note that this device file is <em>not</em> the same as a filesystem mount. well cover mounting later.</p>
<p>with the data disk unplugged, run the command <code>df</code>. plug the disk in, and run <code>df</code> again. compare its output to the previous run. there should be exactly one new entry, and it should look like <code>/dev/sda</code> or <code>/dev/sda2</code>. if youre not sure which disk it is, dont risk it, ask a friend for help.</p>
<!-- todo: where can you find a friend to ask? -->
<p><span class="emoji" data-emoji="warning">⚠️</span> <strong>warning! this will erase everything on the disk!</strong></p>
<p>format the disk, and label it. this will make it easier to mount later.</p>
<pre><code># mkfs.ext4 /dev/sda
# e2label /dev/sda teapot-data</code></pre>
</section>
<section id="mount-storage" class="level2">
<h2>mount storage</h2>
<p>Linux doesnt use drive letters like Windows does. instead, every disks filesystem lives at some <strong>path</strong>. the main, or root path is <code>/</code>, a single slash. the root path belongs to the operating system disk, in this case the MicroSD card. well create a new sub-path at <code>/data</code> for our data disk.</p>
<pre><code># mkdir /data</code></pre>
<p>when the system boots up, it looks in the config file <code>/etc/fstab</code> to find out where we want other filesystems to be loaded. since we gave our disk a label earlier, we can mount it using that label. open the file with <code>nano</code>, and add this line to the end of it:</p>
<pre><code>LABEL=teapot-data /data ext4 nofail,x-systemd.device-timeout=5s,x-systemd.automount 0 0</code></pre>
<p>theres a lot going on here. you can <a href="https://www.freedesktop.org/software/systemd/man/systemd.mount.html#fstab">read more</a> about how fstab and systemd work, but basically what were saying is</p>
<ul>
<li>find the disk labeled teapot-data and mount it at <code>/data</code>, as an ext4 filesystem.</li>
<li>nofail: if the disk is missing at boot time, skip it and finish booting anyway.</li>
<li>x-systemd.device-timeout=5s: wait 5 seconds before giving up.</li>
<li>x-systemd.automount: if someone tries to access the disk and its not mounted, try mounting it again.</li>
</ul>
<p>were using a delayed mounting process here because we want to make sure our server still comes online, even if the disk fails to load. if the server crashes on boot, well have to go plug the monitor and keyboard back in to fix it. with nofail, we have a chance to fix it remotely.</p>
<p>save and exit the file if you havent already, and then check it:</p>
<pre><code># mount --all --fake --verbose</code></pre>
<ul>
<li>all: apply all the rules from <code>/etc/fstab</code>.</li>
<li>fake: dont <em>actually</em> apply the rules, just check that theyre written correctly.</li>
<li>verbose: give detailed feedback. Linux programs typically say nothing unless there is an error.</li>
</ul>
<p>if all your mounts pass inspection, now is a good time to reboot the machine.</p>
<pre><code># reboot</code></pre>
</section>
<section id="backups" class="level2">
<h2>backups</h2>
<p>Ill write a longer section about backups later. basically: every month or so, plug in the second disk, and copy everything from the first disk to the second one. its a quick and dirty solution and its better than having no backups at all. the command you want is</p>
<pre><code>rsync -axHAWXS --numeric-ids --info=progress2 &lt;source&gt; &lt;destination&gt;</code></pre>
<p>explanation <a href="https://superuser.com/a/1185401">here</a>.</p>
</section>
<section id="website" class="level2">
<h2>website</h2>
<p>were getting into the fun stuff now. one of the coolest things you can do with your Linux server is host a website. a little chunk of the world wide web that belongs just to you. all you need to be a website is to have a program running and ready to answer <a href="https://en.wikipedia.org/wiki/HTTP">HTTP</a> requests with <a href="https://en.wikipedia.org/wiki/HTML">HTML</a> text. HTTP is the HyperText Transfer Protocol, and HyperText is just a fancy word for text with <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a">hyperlinks</a> in it.</p>
<p>put briefly: the internet is made of programs that exchange text files with each other!</p>
<p>we could write a web server from scratch, but to get started well use <a href="https://httpd.apache.org">Apache</a>, a free, open-source, and well-established web server. <a href="https://nginx.org">nginx</a> has a free version too, but Apache is good enough for our purposes.</p>
<pre><code># apt install apache2</code></pre>
<p>it should start itself automatically. go ahead and check <a href="http://teapot.local" class="uri">http://teapot.local</a>, and you should see the test page! now well write our own page hosted on the data disk. well make a folder for it called <code>/data/teapot.local</code> and a subfolder of that called <code>site</code>.</p>
<pre><code># mkdir /data/teapot.local
# mkdir /data/teapot.local/site</code></pre>
<p>when making multiple levels of new directories like this, you can use this shortcut to create the whole chain in one go:</p>
<pre><code># mkdir -p /data/teapot.local/site</code></pre>
<p>were about to do a bunch of typing to set up a basic site definition. you can copy and paste this if you want, but I recommend typing it by hand. itll train your brain to recognize pieces of the code. remember, use <code>nano</code> to create or edit text files.</p>
<p>contents of <code>/data/teapot.local/site.conf</code>:</p>
<pre><code>&lt;VirtualHost *:80&gt;
ServerName teapot.local
DocumentRoot /data/teapot.local/site
&lt;Directory /&gt;
Require all granted
&lt;/Directory&gt;
&lt;/VirtualHost&gt;</code></pre>
<p>this is just about the simplest possible website definition. were saying “hi, I am a web server listening to port 80, serving pages for the website teapot.local.” a <strong>port</strong> is like a post office box for a computer. it allows you to address a specific program inside the machine. port 80 is an old and well-known port which is used for most HTTP traffic.</p>
<p>next we define the DocumentRoot to be <code>/data/teapot.local/site</code>, instead of Apaches default of <code>/var/www/html</code>. we also tell Apache that its allowed to share these files. by default, if no filename is specified, Apache will look for one called <code>index.html</code>, so well write that too.</p>
<p>contents of <code>/data/teapot.local/site/index.html</code>:</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;meta charset=&quot;utf-8&quot;&gt;
&lt;title&gt;my website!&lt;/title&gt;
&lt;h1&gt;my website!&lt;/h1&gt;
lorem ipsum dolor sit amet</code></pre>
<p>HTML is what your web browser sees. in fact, if youre on a desktop browser, you can press ctrl-u right now to see the HTML text behind <em>this page!</em> what Ive written for this example is the bare minimum to follow the modern html5 standard.</p>
<ul>
<li>originally the <code>&lt;!DOCTYPE&gt;</code> tag was used to announce what version of html you were using, but these days we dont really care. we just assume everyones using normal html.</li>
<li>the <code>&lt;html&gt;</code> tag is traditional, but in html5 its actually <a href="https://html.spec.whatwg.org/multipage/semantics.html#the-html-element">optional</a>, as is the closing <code>&lt;/html&gt;</code> tag. we include the opening tag here so we can specify <code>lang="en"</code>, which tells the browser that our website is written in English. if you are not writing in English, substitute the appropriate <a href="https://www.w3schools.com/tags/ref_language_codes.asp">language code</a>.</li>
<li>use a <code>&lt;meta&gt;</code> tag to let the browser know were using utf-8. once upon a time there were different text encodings for every language. its really a <a href="https://www.youtube.com/watch?v=MijmeoH9LT4">miracle</a> that utf-8 exists. this encoding was written by the geniuses at <a href="https://home.unicode.org">Unicode</a>. it works great for English, and pretty well for <em>every other text in every known language.</em> if this emoji works (⚠️) and isnt displayed like aE` or something, then you can thank utf-8.</li>
<li>a title! the <code>&lt;title&gt;</code> tag is required in html5. this is the text that appears in your browser tab.</li>
<li>a heading! this is usually the same as the title, but its optional. <code>&lt;h1&gt;</code> is used for the main heading, <code>&lt;h2&gt;</code> for a sub-heading, all the way down to <code>&lt;h6&gt;</code>.</li>
<li>finally, I put some <a href="https://www.lipsum.com">generic text</a> here with no tags at all, just to pad out the page a little.</li>
</ul>
<p>once youve written both of those files, we can tell Apache our site is ready. by the way, when typing these long paths, try pressing tab once or twice, sometimes your shell will auto-complete words. neat!</p>
<pre><code># ln -s /data/teapot.local/site.conf /etc/apache2/sites-available/teapot.local.conf
# a2ensite teapot.local
# a2dissite 000-default
# systemctl reload apache2</code></pre>
<p>now go back to <a href="http://teapot.local" class="uri">http://teapot.local</a> and hit refresh, and you should see your new website! at this point you can go explore the world of HTML. the nice folks at <a href="https://neocities.org/tutorials">Neocities</a> are helping to keep this art alive, go check them out! and remember, you can press ctrl-u to view the HTML for any page youre on.</p>
<p><em>p.s. up until this point Ive been writing with pure HTML myself, but as this page is getting rather long, Im actually switching to a helper tool called <a href="https://pandoc.org/">pandoc</a>. I may cover this tool in a later tutorial.</em></p>
</section>
<section id="networking" class="level2">
<h2>networking</h2>
<p>at this point, your server is available only on your <strong>LAN</strong>, your local area network. this network is managed by your <strong>router</strong>, which is a small computer plugged into your homes internet cable. this cable goes to an internet service provider, or <strong>ISP</strong>, and they take the traffic from your network and connect it to other networks around the world. by default, your router will protect your computers from unwanted traffic. people from around the world cant log into your server, and they also cant see your website. if you want to change that, youll need to change settings on the router.</p>
<p><span class="emoji" data-emoji="warning">⚠️</span> <strong>dont modify a home network without consent!</strong></p>
<p>if you do this wrong it puts <em>everyone</em> on the network at risk, so make sure everyone in your house knows what youre doing. if <em>anyone</em> isnt comfortable, then do not open up your home network! you have lots of other options:</p>
<ul>
<li>host your website with a free host like <a href="https://neocities.org/">Neocities</a> or <a href="https://pages.github.com/">GitHub Pages</a>.</li>
<li>have a friend host instead and share the server with them.</li>
<li>rent a virtual server from a service like <a href="https://www.digitalocean.com/">DigitalOcean</a> or <a href="https://aws.amazon.com/">Amazon Web Services (AWS)</a>.</li>
</ul>
<p>if youre sure you want to open up your home network, read on…</p>
<section id="firewall" class="level3">
<h3>firewall</h3>
<p>if you do everything right, the only server that will be available to the outside world is our little teapot, and only people with an account will be able to get in.</p>
<p><span class="emoji" data-emoji="warning">⚠️</span> <strong>you <em>did</em> pick a long, random passphrase, right? if not, go back and do that <em>now</em>.</strong></p>
<p>however, for a little extra safety, well use <code>ufw</code> to limit what kind of messages teapot will answer. ufw stands for Ubuntu firewall but it works on other systems besides Ubuntu now, so sometimes its called uncomplicated firewall instead.</p>
<p><span class="emoji" data-emoji="bulb">💡</span> I got this information almost verbatim from the <a href="https://www.raspberrypi.com/documentation/computers/configuration.html">Raspberry Pi Foundation</a>, seriously theyre awesome people.</p>
<p>install <code>ufw</code>. unlike other system services, this doesnt start automatically, since you can lock yourself out with it. thats why its important we configure it <em>before</em> changing settings on the router.</p>
<pre><code># apt install ufw</code></pre>
<p>well also need to know the routers local address. we can find this with the <code>ip</code> function.</p>
<pre><code>$ ip route</code></pre>
<p>the first line of the output should look like this:</p>
<pre><code>default via 192.168.20.1 dev eth0</code></pre>
<p>if youre using a wireless connection, youll see wlan0 instead of eth0. underneath the first line, you should see a similar number, but with /24 at the end, like</p>
<pre><code>192.168.20.0/24 dev eth0</code></pre>
<p>this defines the local <strong>subnet</strong>, the list of IPs that count as part of your local area network. the /24 means that the first 24 bits are fixed. there are 8 bits in a byte, so 24 bits is 3 bytes, meaning that this subnet includes all addresses of the form 192.168.20.x.</p>
<p>to avoid locking ourself out, well allow anything from the local area network to connect:</p>
<pre><code># ufw allow from 192.168.20.0/24</code></pre>
<p>substitute your own subnet as appropriate. well also allow http and https traffic through. ufw has built-in rules that say how to handle this traffic, and it will open the right ports for you.</p>
<pre><code># ufw allow http
# ufw allow https</code></pre>
<p>if you want to log in remotely, enable ssh as well:</p>
<pre><code># ufw allow ssh</code></pre>
<p>you can check the list of rules with <code>ufw show added</code>. if all looks good, turn it on:</p>
<pre><code># ufw enable</code></pre>
<p>with any luck, you wont get kicked off your ssh connection, which means the firewall is allowing you through. ufw should now be blocking traffic on all other ports, which will dramatically cut down on the surface area for an attack.</p>
</section>
<section id="private-key-auth" class="level3">
<h3>private key auth</h3>
<p>chances are, even if you want to allow outside ssh connections, you dont really need to be able to log in from <em>anywhere</em>. most likely youll only be logging in from one or two machines, like a laptop or your phone. we can configure our server to only allow authenticated devices to connect.</p>
<p>theres a lot of really advanced math behind private keys, math called <strong>cryptography</strong>, but the important part for our purposes is that each key has a public and a private part. the <strong>public key</strong> can be used to <em>encrypt</em> files, “locking” them, but only the <strong>private key</strong> can <em>decrypt</em>, or “unlock” them. well use this to prove that a device is authorized, by sending a locked message that only it can unlock.</p>
<p>on your laptop or other client device, generate an ssh key. if youre on Linux, Mac OS, or Windows 10, this is probably named <code>ssh-keygen</code>. you can also add a comment to the key, so you remember which device it belongs to.</p>
<pre><code>$ ssh-keygen -t ed25519 -C &quot;my laptop&quot;</code></pre>
<p>follow the prompts to generate a private key. it will be saved in <code>/home/user/.ssh</code> (or your operating systems equivalent location), as well as a public key with a .pub file extension. you can add a passphrase during key generation, this is highly recommended if anyone else has access to your computer!</p>
<p>well need to get the public key, the one ending in .pub, onto the server somehow so it can recognize us. public keys dont need to be kept secret, so use any type of file transfer available to you. you could copy it to a USB drive and plug it into the server, or copy it by hand, or even send it to yourself over the public internet. once you get it to the server, create the file <code>~/.ssh/authorized_keys</code>. on a new line, <strong>copy the full contents of the .pub file into the authorized_keys file.</strong></p>
<p><span class="emoji" data-emoji="bulb">💡</span> if you need to connect from multiple devices, I recommend repeating these steps for each device, rather than copying your private key between devices. that way you dont have to worry about accidentally leaking your private key. you can add as many public keys to <code>authorized_keys</code> as you want!</p>
<p>at this time, try logging into the server from the newly-authorized client. it will ask for your keys passphrase if you set one, but it <em>wont</em> ask for your account passphrase, since you already authenticated yourself by having the private key. you will still need to type your password to use sudo though, just in case.</p>
<p>if that went well, you can now disable password-based auth completely. as admin, open <code>/etc/ssh/sshd_config</code> and make sure this is set to no:</p>
<pre><code>PasswordAuthentication no</code></pre>
<p>save the file, and restart the ssh service:</p>
<pre><code># service ssh reload</code></pre>
<p>it should now be impossible to login without an authorized key. if you want to authorize more devices, repeat these steps for each device. each device should have its own private key. never let a private key leave the device that created it. if you accidentally copy a private key, remove it from authorized_keys and create a new one to replace it.</p>
</section>
<section id="port-forwarding" class="level3">
<h3>port forwarding</h3>
<p><span class="emoji" data-emoji="warning">⚠️</span> <strong>dont do this until youve done everything else!</strong></p>
<p>its time to make the big leap. your server is armored up and ready to face the outside world. lets open the gates. the end goal here is to forward ports 80 and 443, from the outside world to your server. if you want to log in remotely, youll also need to forward port 22.</p>
<p>unfortunately, port forwarding is going to be a bit different for every router. Ill share what worked for my router, a <a href="https://mikrotik.com/">MikroTik</a> running RouterOS.</p>
<ul>
<li>connect to the router web interface at <a href="http://router.lan" class="uri">http://router.lan</a>.</li>
<li>switch from Quick Set to WebFig view.</li>
<li>Go to IP -&gt; DHCP Server -&gt; Leases.
<ul>
<li>find the local address assigned to teapot. this should look like 192.168.x.x, or possibly 10.0.x.x.</li>
<li>click on that address, and select make static. this way, when teapot disconnects and reconnects, it will always get the same address. in my case it was 192.168.88.247.</li>
</ul></li>
<li>Go to IP -&gt; Firewall -&gt; NAT -&gt; New Rule.
<ul>
<li>Chain: dstnat</li>
<li>Dst. Address: &lt;your public IP address&gt;</li>
<li>Protocol: 6 (tcp)</li>
<li>Dst. Port: 80</li>
<li>Action: dst-nat</li>
<li>To Addresses: &lt;teapots local IP address&gt;</li>
<li>To Ports: 80</li>
</ul></li>
<li>Repeat that step for port 443.</li>
<li>If you need remote login, repeat that step again for port 22.</li>
</ul>
<p>while were configuring the router, well enable <strong>hairpin NAT</strong>, also known as <strong>NAT reflection</strong> or <strong>NAT loopback</strong>. without this rule, the router may get confused if we try to access teapot via its <em>public</em> address while we are inside the <em>local</em> network.</p>
<ul>
<li>Go to IP -&gt; Firewall -&gt; NAT -&gt; New Rule (again):
<ul>
<li>Chain: srcnat</li>
<li>Src. Address: 192.168.88.0/24 (use your own subnet)</li>
<li>Dst. Address: &lt;teapots local IP address&gt;</li>
<li>Protocol: 6 (tcp)</li>
<li>Out. Interface List: LAN</li>
<li>Action: masquerade</li>
</ul></li>
</ul>
<p>you should now be able to go to http://&lt;your own public IP address&gt;, and your router will forward the traffic to teapot. congratulations, your machine is now a true part of <strong><em>the internet.</em></strong></p>
</section>
<section id="https" class="level3">
<h3>https</h3>
<p>todo:</p>
<ul>
<li>get a domain name from a service like <a href="https://afraid.org" class="uri">https://afraid.org</a></li>
<li>set up https with a service like LetsEncrypt
<ul>
<li>apt install certbot python3-certbot-apache</li>
<li>certbot certonly apache</li>
<li>a2enmod rewrite ssl</li>
</ul></li>
</ul>
</section>
</section>
<section id="file-sharing" class="level2">
<h2>file sharing</h2>
<p>another neat thing you can do with your server is use it to store stuff! there are some all-in-one solutions for this such as <a href="https://nextcloud.com/">NextCloud</a>, but right now thats overkill for me; I want to install simple tools to solve simple problems.</p>
<section id="sync" class="level3">
<h3>sync</h3>
<p><a href="https://syncthing.net/">Syncthing</a> is a simple tool for duplicating some folders across multiple devices. maybe you want all your photos to be automatically duplicated from your phone to your server, or you have some game save files that you want to be copied between two gaming pcs, or you have some other documents that you access frequently from your laptop and your desktop. Syncthing is one of those rare and beautiful gems of free software that just works.</p>
<p>as admin, install the service:</p>
<pre><code># apt install syncthing
# ufw allow syncthing</code></pre>
<p>as your normal user account, enable the service for yourself:</p>
<pre><code>$ systemctl --user enable syncthing
$ systemctl --user start syncthing</code></pre>
<p>thats it! Syncthing is now installed and running! you can configure Syncthing with a web app that runs on port 8384. if youre connected remotely via ssh, use this trick to get access. type the special sequence [enter], tilde (~), C (shift+c), and youll get a prompt like</p>
<pre><code>ssh&gt;</code></pre>
<p>well use this prompt to set up a temporary tunnel. a <strong>tunnel</strong> allows you to bind a port on your client machine to a client on the server. specifically, a tunnel passes some traffic through your encrypted ssh connection, as opposed to passing it through a browser via http or https. this way you can quickly get access to an application running on your server, without exposing it to the whole internet. for this example, well bind the clients port 8000 to localhost:8384 on the server.</p>
<pre><code>ssh&gt; -L 8000:localhost:8384</code></pre>
<p>now, open <a href="http://localhost:8000" class="uri">http://localhost:8000</a> on your client, and you should have access to the Syncthing console running on the server!</p>
<p><span class="emoji" data-emoji="bulb">💡</span> you can also send this command to ssh at login time. for instance:</p>
<pre><code>$ ssh user@teapot -L 8000:localhost:8384</code></pre>
<hr />
<p>syncthing todo:</p>
<ul>
<li>explain my personal folder setup</li>
<li>versioning options, and how this is not the same as a proper backup (but its close)</li>
</ul>
<p>file sharing todo:</p>
<ul>
<li>set up samba share</li>
<li>configure nfs</li>
<li><a href="https://github.com/filebrowser/filebrowser">FileBrowser</a>
<ul>
<li>set up auth before exposing this to the internet, I think</li>
</ul></li>
</ul>
</section>
</section>
<section id="containers" class="level2">
<h2>containers</h2>
<p>at this point, well take a detour and talk about containers. everything weve done so far has involved making changes to system files. if you need to copy your data to a new system youll have to change all those system files again, and this gets more complicated the more things are installed. thankfully, many applications can now be installed as containers.</p>
<p>a <strong>container</strong> isnt quite a virtual machine. youre not running a whole computer-inside-a-computer. its more like a facade, a fake computer with a fake filesystem and fake network. containers dont take much memory to create, and they dont leave junk all over the filesystem when you remove them. neat!</p>
<p>well be using <a href="https://podman.io">Podman</a>, a container host service. if youre familiar with <a href="https://www.docker.com">Docker</a>, this is like that, but even <em>more</em> free.</p>
<pre><code># apt install podman python3-pip
# pip install &quot;podman-compose&lt;1.0&quot;</code></pre>
<ul>
<li>pip is a package manager for <a href="https://www.python.org">Python</a> programs. we install pip so that we can use it to install podman-compose.</li>
<li><a href="https://github.com/containers/podman-compose#podman-compose">podman-compose</a> is a very handy tool that lets you store your container instructions in a script file to use later. well cover this soon. I needed to specify an old version for compatibility.</li>
<li>if you are on armbian, you may also need to install <code>uidmap</code> and <code>slirp4netns</code> manually. these are normally included with podman and are used for making fake users and fake networks, respectively.</li>
</ul>
<p>well test Podman by running a copy of <a href="https://nginx.org">nginx</a> (pronounced engine-x). well use the image published by <a href="https://hub.docker.com">Docker Hub</a>. think of an <strong>image</strong> as a casting mold. you cant run an image directly, but you can use it to produce a filled container.</p>
<pre><code>$ podman run --rm -p 8000:80 docker.io/library/nginx</code></pre>
<ul>
<li><code>podman run</code>: create a new container and start it immediately.</li>
<li><code>--rm</code>: remove the container automatically when the main program exits.</li>
<li><code>-p 8000:80</code>: connect port 8000 on the host to port 80 inside the container. we need permission to bind to ports less than 1024, since theyre older and have special meanings. without that permission, we can use any port between 1024 and 65535. 8000 is an arbitrary choice, and its easy to remember.</li>
<li><code>docker.io/library/nginx</code>: this is the name of the image were building. this has to come last, because anything that comes after the image is instructions for the program inside the container, not for Podman. in this case were not giving any instructions after the image, because we want to run the default command, which is to immediately start nginx.</li>
</ul>
<p><span class="emoji" data-emoji="bulb">💡</span> if you get an error like “delete libpod local files to resolve”, you may need to do this extra step, then try again:</p>
<pre><code>$ sudo rm ~/.local/share/containers</code></pre>
<p>you should now be able to point a web browser at <a href="http://teapot.local:8000" class="uri">http://teapot.local:8000</a> and you will see nginx is running!</p>
<p>finally, well use podman-compose to save this setup. create a folder in <code>/data</code> for this container, and make a new file called <code>compose.yaml</code>.</p>
<p>contents of <code>/data/nginx/compose.yaml</code>:</p>
<pre><code>version: &#39;3&#39;
services:
nginx:
image: docker.io/library/nginx
ports:
- 8000:80</code></pre>
<p>this does the same thing as our command from before. it starts one service container, running nxing, with port 8000 on the host mapped to port 80 in the container. to run this script, type</p>
<pre><code>$ podman-compose up -d</code></pre>
<p>and to stop it again:</p>
<pre><code>$ podman-compose down</code></pre>
</section>
<section id="database" class="level2">
<h2>database</h2>
<p>todo:</p>
<ul>
<li>explain why and how to host a database</li>
<li>install php and mariadb</li>
<li>configure phpmyadmin</li>
</ul>
</section>
<section id="apps" class="level2">
<h2>apps</h2>
<p>todo:</p>
<ul>
<li>recommend some other apps like gitea, freshrss</li>
<li>serve apps through apache ProxyPass</li>
<li>see also <a href="https://github.com/awesome-selfhosted/awesome-selfhosted">awesome self-hosted</a> and <a href="https://github.com/awesome-foss/awesome-sysadmin">awesome sysadmin</a> software.</li>
</ul>
</section>
<section id="auth" class="level2">
<h2>auth</h2>
<p>todo:</p>
<ul>
<li>set up <a href="https://www.keycloak.org">Keycloak</a> so you can log in through the reverse proxy.</li>
</ul>
</section>
</body>
</html>

39
static/cookbook/style.css Normal file
View file

@ -0,0 +1,39 @@
:root {
/* xkcd.com/color/rgb */
--amber: #feb308;
--black: #000000;
--steel-blue: #5a7d9a;
--olive-green: #677a04;
--grey: #929591;
--warm-grey: #978a84;
--light-grey: #d8dcd6;
--background: var(--black);
--foreground: var(--light-grey);
--code: var(--amber);
--link: var(--steel-blue);
font-family: sans-serif;
color: var(--foreground);
background-color: var(--background);
max-width: 100ch;
margin: auto;
padding: 1ch;
}
a {
color: var(--link);
}
code {
color: var(--code);
font-size: 1rem;
}
pre, pre.sourceCode {
color: var(--code);
margin: 2ch;
white-space: pre-wrap;
border: solid 1.5px;
padding: 2ch;
}
section.level2 {
border-top: 0.5ch solid white;
}

View file

@ -0,0 +1,117 @@
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<style>
body {
font-size: 30px;
font-family: Calibri, sans-serif;
font-weight: bold;
text-align: center;
border: #000 solid 10px;
width: 500px;
height: 700px;
margin: 10px auto;
}
table {
margin: 0px auto;
}
td:first-of-type {
text-align: left;
min-width: 16ch;
}
td:not(:first-of-type) {
min-width: 2ch;
}
.border {
color: white;
background-color: white;
text-shadow:
-1px -1px 0 #000,
1px -1px 0 #000,
-1px 1px 0 #000,
1px 1px 0 #000;
}
footer {
font-size: 10px;
}
</style>
<br> <!-- Look, vertical alignment is hard ok -->
<table>
<th colspan="6">Poker Hands</th>
<tr>
<td>Straight Flush</td>
<td class="border">A</td>
<td class="border">2</td>
<td class="border">3</td>
<td class="border">4</td>
<td class="border">5</td>
</tr>
<tr>
<td>Four of a Kind</td>
<td>Q</td>
<td>Q</td>
<td>Q</td>
<td>Q</td>
<td>8</td>
</tr>
<tr>
<td>Full House</td>
<td>3</td>
<td>3</td>
<td>3</td>
<td>2</td>
<td>2</td>
</tr>
<tr>
<td>Flush</td>
<td class="border"></td>
<td class="border"></td>
<td class="border"></td>
<td class="border"></td>
<td class="border"></td>
</tr>
<tr>
<td>Straight</td>
<td>10</td>
<td>J</td>
<td>Q</td>
<td>K</td>
<td>A</td>
</tr>
<tr>
<td>Three of a Kind</td>
<td>K</td>
<td>K</td>
<td>K</td>
<td>8</td>
<td>A</td>
</tr>
<tr>
<td>Two Pairs</td>
<td>A</td>
<td>A</td>
<td>7</td>
<td>7</td>
<td>5</td>
</tr>
<tr>
<td>One Pair</td>
<td>Q</td>
<td>Q</td>
<td>4</td>
<td>6</td>
<td>9</td>
</tr>
</table>
<p>
Ties broken by highest card.
<br> Matched sets have priority.
<br> Aces are high, except in A2345.
</p>
<p>
<span class=border>99</span>542 >
<span class=border>88</span>A6<span class="border">4</span> >
88A6<span class="border">3</span>
</p>
<footer>©Nick 'nupa' Lamicela, 2023</footer>

44
static/russet/index.html Normal file
View file

@ -0,0 +1,44 @@
<!doctype html>
<html>
<head>
<title>Nupa's Page</title>
<meta charset='utf-8'/>
<link rel='stylesheet' href='../style.css'>
</head>
<body>
<main>
<header>
<h1>Russet</h1>
<div class="subtitle">Or, how to reproduce my self-host server.</div>
</header>
<section>
<h2>Hardware</h2>
<p>
Russet runs on a Raspberry Pi, model 4b with 4GB RAM. It has an Argon metal heat dispersing shell. It's hooked up to a Microtik router over a wired home internet connection. You can use any small computer really. If Raspberry Pi is currently hard to obtain (2022) then I recommend the Pine64 "Rock64" computer as an alternative.
</p>
</section>
<section>
<h2>Operating System</h2>
<p>
There are hundreds of guides on how to install Raspbian (or Armbian) on various systems. It usually boils down to "go download a disk image and write it to an sd card using some disk writing tool". I'll assume you can figure this part out without my help. The important thing for our purposes is that your OS is debian-based, so we have access to the now-familiar 'apt' package mananger (sorry, Arch fans).
</p>
</section>
<!--
TODO:
- Configure sshd
- Manage apps with Podman
- Reverse proxy with Nginx
-->
<section>
<h2>Changelog</h2>
<p>2022-12-13: New page.</p>
</section>
</main>
</body>
</html>