summaryrefslogtreecommitdiff
path: root/content
diff options
context:
space:
mode:
Diffstat (limited to 'content')
-rw-r--r--content/_index.md45
-rw-r--r--content/auth.md136
-rw-r--r--content/bandwidth.md88
-rw-r--r--content/basic/certbot.md132
-rw-r--r--content/basic/dns.md96
-rw-r--r--content/basic/domain.md75
-rw-r--r--content/basic/nginx.md212
-rw-r--r--content/basic/server.md97
-rw-r--r--content/bitcoin.md105
-rw-r--r--content/btcpay.md57
-rw-r--r--content/calibre.md116
-rw-r--r--content/cgi.md210
-rw-r--r--content/cgit.md135
-rw-r--r--content/coturn.md111
-rw-r--r--content/cron.md173
-rw-r--r--content/ejabberd.md259
-rw-r--r--content/federation.md57
-rw-r--r--content/fosspay.md183
-rw-r--r--content/gemini.md189
-rw-r--r--content/git.md131
-rw-r--r--content/gitea.md161
-rw-r--r--content/html.md143
-rw-r--r--content/html2.md7
-rw-r--r--content/html4.md32
-rw-r--r--content/i2p.md101
-rw-r--r--content/imgcompress.md51
-rw-r--r--content/irc.md946
-rw-r--r--content/jitsi.md199
-rw-r--r--content/mail/dovecot.md112
-rw-r--r--content/mail/opendkim.md187
-rw-r--r--content/mail/rainloop.md117
-rw-r--r--content/mail/rdns.md35
-rw-r--r--content/mail/smtp.md70
-rw-r--r--content/maintenance.md124
-rw-r--r--content/matrix.md139
-rw-r--r--content/monero.md89
-rw-r--r--content/movim.md116
-rw-r--r--content/networking.md340
-rw-r--r--content/nextcloud.md292
-rw-r--r--content/nginx-tweaks.md45
-rw-r--r--content/openalias.md102
-rw-r--r--content/page-quality.md180
-rw-r--r--content/peertube.md284
-rw-r--r--content/pleroma.md186
-rw-r--r--content/prosody.md272
-rw-r--r--content/radicale.md105
-rw-r--r--content/rss-bridge.md114
-rw-r--r--content/rss-feed.md95
-rw-r--r--content/rsync.md104
-rw-r--r--content/searxng.md148
-rw-r--r--content/selfhosting.md202
-rw-r--r--content/sshkeys.md153
-rw-r--r--content/standalone.md40
-rw-r--r--content/tor.md119
-rw-r--r--content/ufw.md223
-rw-r--r--content/yarr.md101
56 files changed, 8341 insertions, 0 deletions
diff --git a/content/_index.md b/content/_index.md
new file mode 100644
index 0000000..41f6971
--- /dev/null
+++ b/content/_index.md
@@ -0,0 +1,45 @@
+
+This is LandChad.net, a site dedicated to turning internet peasants into Internet Landlords by showing them how to setup websites, email servers, chat servers and everything in between.
+
+Starting a website is something that can be done in a lazy afternoon and costs pocket change.
+
+Most of the internet's problems could be solved if more people had their own personal platforms, so the objective of this site is to guide any normal person through the process of installing a website.
+
+## Start a website
+
+<div>
+
+<div class=left>
+
+This is the basic "course." Follow these quick tutorials and you'll have a fully functioning basic web page on the domain name of your choice.
+
+⏳ This "basic course" can take **as little as an hour** or even less.
+
+</div>
+
+<div class=right>
+
+{{< basic >}}
+
+</div>
+
+</div>
+
+
+
+## "Build your own platform!"
+
+{{< services >}}
+
+Host your own services, social media and more.
+
+## Maintaining a Server
+
+Tips and articles on mastering your server and learning about GNU/Linux systems administration.
+
+{{< maintain >}}
+
+## Support LandChad.net
+
+- BTC: `bc1q9f3tmkhnxj8gduytdktlcw8yrnx3g028nzzsc5`
+- XMR: `84RXmrsE7ffCe1ADprxLMHRpmyhZuWYScDR4YghE8pFRFSyLtiZFYwD6EPijVzD3aZiEpg57MfHEr1pGJNPXyJgENMnWrSh`
diff --git a/content/auth.md b/content/auth.md
new file mode 100644
index 0000000..88a5fee
--- /dev/null
+++ b/content/auth.md
@@ -0,0 +1,136 @@
+---
+title: "Requiring Passwords for Webpages (HTTP Authentication)"
+date: 2020-07-01
+img: 'auth.svg'
+tags: ['server']
+---
+
+HTTP basic authentication will allow you to secure parts (or all) of
+your website with a username and password without the trouble of PHP or
+Javascript. This will work with any Nginx server.
+
+## Installation
+
+We will be using the command `htpasswd` to make username and password
+pairs.
+
+```sh
+apt install apache2-utils
+```
+
+The apache utils include a small username-password pair encryption tool.
+
+Like the other tutorials on this site, this tutorial is for Nginx,
+**not** for Apache servers.
+
+Now think of a username and password and remember them.
+
+ htpasswd -c /etc/nginx/myusers username
+
+The `-c` flag creates a file. You can make the path of this file
+anywhere outside of your webroot.
+
+Obviously the username is up to you as well.
+
+Type out your password twice to confirm. You can do this as many times
+as you\'d like.
+
+Check out user name password pairs (the password will be securely
+hashed):
+
+ cat /etc/nginx/myusers
+
+## Nginx Config and Auth Basic
+
+From here, we are going to edit our websites config file in
+`/etc/nginx/sites-enabled`. Have in mind which folder you\'d like to
+secure. Add something like this:
+
+```nginx
+server {
+ #...
+ location /secret-folder {
+ auth_basic "What's the Password?" ;
+ auth_basic_user_file /etc/nginx/myusers ;
+ }
+ #...
+}
+```
+
+#### Huh?
+
+If you\'re stuck, try finding the line `location / {`
+
+Just below this block is where you should add the custom location block
+
+If you\'d like to do the opposite, such as making the entire site
+private except for a public section, do this:
+
+```nginx
+server {
+ #...
+ auth_basic "What's the Password?" ;
+ auth_basic_user_file /etc/nginx/myusers ;
+ location /public/ {
+ #...
+ auth_basic off ;
+ }
+ #...
+}
+```
+
+### IP Addresses
+
+If passwords aren\'t enough we can ban an ip or accept one.
+
+```nginx
+location /api {
+ #...
+ allow 192.168.1.23:8080 ;
+ deny 127.0.0.1 ;
+}
+```
+
+If you want to check both a username and password with an ip address,
+use the `satisfy` directive.
+
+```nginx
+location /api {
+ #...
+ satisfy all ;
+
+ allow 192.168.1.23:8080 ;
+ deny 127.0.0.1 ;
+
+ auth_basic "What's the Password?" ;
+ auth_basic_user_file /etc/nginx/myusers ;
+}
+```
+
+### Complete Example
+
+```nginx
+http {
+ server {
+ listen 80;
+ root /var/www/website ;
+
+ #...
+ location /secret-folder {
+ satisfy all ;
+
+ allow 192.168.1.3/24;
+ deny 127.0.0.1 ;
+
+ auth_basic "What's the Password?" ;
+ auth_basic_user_file /etc/nginx/myusers ;
+ }
+ }
+}
+```
+
+Now check your configuration with `nginx -t`
+
+Reload nginx and you\'re good to go!
+
+**Contributor** - [tomfasano.net](https://tomfasano.net)
diff --git a/content/bandwidth.md b/content/bandwidth.md
new file mode 100644
index 0000000..2313524
--- /dev/null
+++ b/content/bandwidth.md
@@ -0,0 +1,88 @@
+---
+title: "Loading Fast and Saving Bandwidth"
+draft: true
+---
+## Images
+
+Image files will usually have the most impact on the speed of your
+websites (aside from Ad/tracker scripts). Learn to slim down your images
+using the ubiquitous *ImageMagick* to make your websites faster on slow
+internet connections.
+
+![Image network speed](pix/imgcompress-network.png)
+
+There are some rules of thumb to keep in mind with images:
+
+1. Only use images as large as you need on the webpage.
+2. Use the proper containers. E.g. a photograph should never be a
+ `.png`, but a `.jpg`, or even better, a `.webp`.
+3. Where it will not be visible, reduce image quality.
+
+### webp vs. png vs. svg
+
+`png` images are best for accurately recording images **without color
+gradients**. A `png` photograph will be massive in size, but a `png`
+cartoon without color
+
+#### An imagemagick experiment
+
+We can illustrate this difference with imagemagick. Run the following
+two commands. They will create two png files containing nothing by the
+color red. The first will create a 100x100 pixel image, and the second
+will create a massive 10,000x10,000 image. (The second command will take
+a few seconds to finish.)
+
+ magick -size 100x100 canvas:red red-small.png
+ magick -size 10000x10000 canvas:red red-large.png
+
+Once we\'ve done that, let\'s rerun the same commands, except for let\'s
+output them into `jpg` containers:
+
+ magick -size 100x100 canvas:red red-small.jpg
+ magick -size 10000x10000 canvas:red red-large.jpg
+
+Once we\'ve run all those commands, you will see that `red-large.jpg` is
+a massive 1.2M, while `red-large.png`, despite still being 10,000 square
+pixels like the jpg, is a mere 13K in filesize.
+
+------------------------------------------------------------------------
+
+For the examples, I decided to use
+[this](https://commons.wikimedia.org/wiki/File:Tabby_cat_with_blue_eyes-3336579.jpg)
+public domain image.
+
+![Compressed image of a
+cat](https://upload.wikimedia.org/wikipedia/commons/thumb/c/c7/Tabby_cat_with_blue_eyes-3336579.jpg/499px-Tabby_cat_with_blue_eyes-3336579.jpg){style="width: 50%;"}
+
+There are many ways to decrease image size using ImageMagick, the
+simplest is to use the `-quality` option, which will compress the image
+without changing the resolution. This option takes the value you want to
+compress by (between 1 and 100, the lower the value, the lower the file
+size). For example:
+
+ convert in.jpg -quality 50 out.jpg
+
+Compressing the example image above results in the following file size
+changes:
+
+ Quality Size
+ ---------- ------
+ Original 2.1M
+ 90 1.7M
+ 80 844K
+ 70 588K
+ 60 448K
+ 50 368K
+ 40 308K
+ 30 248K
+ 20 184K
+ 10 116K
+
+Due to the images high resolution, it is usable in this website even
+when highly compressed (30% quality, still looks decent in my opinion).
+
+## Contribution
+
+- [Musse](https://na20a.neocities.org/)
+- Monero:
+ `83is3y69Xv4fkFsTpZhw5c3bfxtimupfgTdpERHM1WtMNAwSqFjTCJm3VabyBKXKnL873dWPmqj4bRcgkm9oCktgQrzmhHd`{.crypto}
diff --git a/content/basic/certbot.md b/content/basic/certbot.md
new file mode 100644
index 0000000..3b60ea7
--- /dev/null
+++ b/content/basic/certbot.md
@@ -0,0 +1,132 @@
+---
+title: "Certbot and HTTPS"
+date: 2021-07-13
+tags: ['basic']
+---
+Once you have a website, it is extremely important to enable encrypted
+connections over HTTPS/SSL. You might have no idea what that means, but
+it\'s easy to do now that we\'ve [set our web server up](nginx.html).
+
+Certbot is a program that automatically creates and deploys the
+certificates that allow encrypted connections. It used to be painful
+(and often expensive) to do this, but now it\'s all free and automatic.
+
+## Why is encryption important?
+
+- With HTTPS, users\' ISPs cannot snoop on what they are looking at on
+ your website. They know that they have connected, but the particular
+ pages they visit are private as everything is encrypted. HTTPS
+ increases user privacy.
+- If you later create usernames and passwords for any service on your
+ site, lack of encryption can compromise that private data! Most
+ well-designed software will automatically *prevent* any unencrypted
+ connections over the internet.
+- Search engines like Google favor pages with HTTPS over unencrypted
+ HTTP.
+- You get the official-looking green πŸ”’ symbol in the URL bar in most
+ browsers which makes normies subtly trust your site more.
+
+## Let\'s do it!
+
+{{< img alt="website without https/ssl" src="/pix/nginx-website.png" link="/pix/nginx-website.png" >}}
+
+Note in this picture that a browser accessing your site will say \"Not
+secure\" or something else to notify you that we are using an
+unencrypted HTTP connection rather than an encrypted HTTPS one.
+
+## Installation
+
+Just run:
+
+```sh
+apt install python3-certbot-nginx
+```
+
+And this will install `certbot` and its module for `nginx`.
+
+## Run
+
+As I mentioned in the previous article, firewalls might interfere with
+certbot, so you will want to either disable your firewall or at least
+ensure that it allows connections on ports 80 and 443:
+
+```sh
+ufw allow 80
+ufw allow 443
+```
+
+Now let\'s run certbot:
+
+```sh
+certbot --nginx
+```
+
+The command will ask you for your email. This is so when the
+certificates need to be renewed in three months, you will get an email
+about it. You can set the certificates to renew automatically, but it\'s
+a good idea to check it the first time to ensure it renewed properly.
+You can avoid giving your email by running the command with the
+`--register-unsafely-without-email` option as well.
+
+Agree to the terms, and optionally consent to give your email to the EFF
+(I recommend against this obviously).
+
+Once all that is done, it will ask you what domains you want a
+certificate for. You can just press enter to select all.
+
+{{< img alt="activate HTTPS for a site with certbot" src="/pix/certbot-01.png" link="/pix/certbot-01.png" >}}
+
+It will take a moment to create the certificate, but afterwards, you
+will be asked if you want to automatically redirect all connections to
+be encrypted. Since this is preferable, choose 2 to Redirect.
+
+{{< img alt="redirecting http to encrypted https with certbot" src="/pix/certbot-02.png" link="/pix/certbot-02.png" >}}
+
+### Checking for success
+
+You should now be able to go to your website and see that there is a
+πŸ”’ lock icon or some other notification that you are now on an encrypted
+connection.
+
+{{< img alt="A πŸ”’ symbol symbolizing our new HTTPS layer for our website!" src="/pix/certbot-03.png" link="/pix/certbot-03.png" >}}
+
+## Setting up certificate renewal
+
+As I mentioned in passing, the Certbot certificates last for 3 months.
+To renew certificates, you just have to run `certbot --nginx renew` and
+it will renew any certificates close to expiry.
+
+Of course, you don\'t want to have to remember to log in to renew them
+every three months, so it\'s easy to tell the server to automatically
+run this command. We will use a [cronjob](/cron) for this. Run the
+following command:
+
+```sh
+crontab -e
+```
+
+There might be a little menu that pops up asking what text editor you
+prefer when you run this command. If you don\'t know how to use vim,
+choose `nano`, the first option.
+
+This `crontab` command will open up a file for editing. A crontab is a
+list of commands that your operating system will run automatically at
+certain times. We are going to tell it to automatically try to renew our
+certificates every month so we never have to.
+
+Create a new line at the end of the file and add this content:
+
+```txt
+0 0 1 * * certbot --nginx renew
+```
+
+Save the file and exit to activate this cronjob.
+
+For more on cron and crontabs please [click here!](/cron)
+
+You now have a live website on the internet. You can add to it what you
+wish.
+
+As you add content to your site, there are many other things you can
+also install linked on [the main page](/), and many more
+improvements, tweaks and bonuses.
diff --git a/content/basic/dns.md b/content/basic/dns.md
new file mode 100644
index 0000000..c6d3d42
--- /dev/null
+++ b/content/basic/dns.md
@@ -0,0 +1,96 @@
+---
+title: "Connect Your Domain and Server with DNS Records"
+date: 2021-07-07
+tags: ['basic']
+---
+## The Gist
+
+Now that we have a [domain](/basic/domain) and a [server](/basic/server), we
+can connect the two using DNS records. DNS (domain name system) records
+are usually put into your registrar and direct people looking up your
+website to the server where your website and other things will be.
+
+Get your IPv4/IPv6 addresses from Vultr and put them into A/AAAA records
+on Epik. Simple process, takes a minute, but here\'s a guide with a
+million images just so you know.
+
+## Open up your Registrar
+
+As before, we will be using
+[Epik](https://www.epik.com/?affid=we2ro7sa6) as a registrar and
+[Vultr](https://www.vultr.com/?ref=8384069-6G) as a server host. Go
+ahead and log into your accounts on both. Open up Epik, or your
+registrar, and click on your domain and then a choice for \"DNS
+records.\" This is the screen you\'ll want to see on Epik.
+
+{{< img alt="Blank Epik DNS records" src="/pix/dns-epik.png" link="/pix/dns-epik.png" >}}
+
+Note that we are on the \"External Hosts (A, AAAA)\" tab by default.
+Epik sometimes adds records to this page once you buy a domain. If they
+did, you can go ahead and delete them so they look clean like the
+picture above.
+
+**All we have to do now is get our IP addresses from Vultr and add new
+DNS records that will send connections to our server.**
+
+Keep the Epik tab open and open Vultr and we will copy-and-paste our IP
+addresses in.
+
+## Find your server\'s IP addresses
+
+Looking at your server in the Vultr menu, you should see a number next
+to it. Mine here is `104.238.126.105` as you can see below the server
+name (which I have named `landchad.net` after the domain I will soon
+attach to it). That is my **IPv4** address.
+
+{{< img src="/pix/dns-ipv4.png" alt="See the IPv4 address?" link="/pix/dns-ipv4.png" >}}
+
+Copy your IPv4 address and on Epik, click the \"Add Record\" record
+button and add two A entries pasting in your IPv4 address like I\'ve
+done for mine here.
+
+{{< img src="/pix/dns-ipv4-done.png" alt="IPv4 complete" link="/pix/dns-ipv4-done.png" >}}
+
+I add two entries. One has nothing written in the \"Host\" section. This
+will direct connections to `landchad.net` over IPv4 to our IP address.
+The second has a `*` in the \"Host\" section. This will direct
+connections to all possible subdomains to the right place too, I mean
+`mail.landchad.net` or `blog.landchad.net` and any other subdomain we
+might want to add later.
+
+Now let\'s get our IPv6 address, which is a little more hidden for some
+reason. IPv6 is important because we are running out of IPv4 addresses,
+so it is highly important to allow connections via IPv6 as it will be
+standard in the future. Anyway, now back on Vultr, click on the server
+name.
+
+On the server settings, **click on settings** and we will see we are on
+a submenu labeled \"IPv4\" where we see our IPv4 address again.
+
+{{< img src="/pix/dns-vultr.png" alt="Looking for the IPv6" link="/pix/dns-vultr.png" >}}
+
+Now just click on the **IPv6** submenu to reveal your IPv6 address.
+
+{{< img alt="The IPv6 address" src="/pix/dns-ipv6.png" link="/pix/dns-ipv6.png" >}}
+
+That ugly looking sequence of numbers and letters with colons in between
+(`2001:19f0:5:ccc:5400:03ff:fe58:324a`) is my **IPv6** address. Yours
+will look something like it. Now let\'s put it into Epik. This time, be
+sure to select to put in AAAA records as below:
+
+{{< img src="/pix/dns-ipv6-done.png" alt="IPv6 complete" link="/pix/dns-ipv6-done.png" >}}
+
+Now just click \"Save Changes.\" It might take a minute for the DNS
+settings to propagate across the internet.
+
+## Test it out!
+
+Now we should have our domain name directing to our new server. We can
+check by pinging our domain name, check this out:
+
+{{< img src="/pix/dns-ping.png" alt="Pinging landchad.net" link="/pix/dns-ping.png" >}}
+
+As you can see, our ping to `landchad.net` is now being directed to
+`104.238.128.105`. That means we have successfully set up our DNS
+records! You can also run the command `host` if you have it, which will
+list both IPv4 and IPv6 addresses for a domain name.
diff --git a/content/basic/domain.md b/content/basic/domain.md
new file mode 100644
index 0000000..67cdd79
--- /dev/null
+++ b/content/basic/domain.md
@@ -0,0 +1,75 @@
+---
+title: "Get a Domain Name"
+tags: ['basic']
+date: 2021-06-01
+---
+## Terms
+
+Domain name
+: The name of a website that you type in an address bar. This site\'s
+ domain name is `LandChad.net`.
+
+Top-level domain (TLD)
+: The extension of a domain name, like `.com`, `.net`, `.xyz`, etc.
+
+Registrar
+: A service authorized to reserve a domain name for you.
+
+When domain names first sell, they usually sell for very cheap, but once
+someone buys one, they have the rights to it until they decide to sell
+it, often for much, much more money. Therefore, it\'s a good idea to
+reserve a domain name ASAP, even if you didn\'t intend on doing anything
+big with it.
+
+So let\'s register your domain name!
+
+## How
+
+Domains can be registered at any accredited <dfn>registrar</dfn>. In this
+guide, I will use the registrar
+[Epik](https://www.epik.com/?affid=we2ro7sa6) because it is one of the
+more high quality and easy to use. The guides on this site will use
+Epik, but if you choose to register your domain with one of the [many,
+many other registrars](https://www.icann.org/en/accredited-registrars),
+you can still do most of what Epik does, albeit options and settings
+might appear in different menus.
+
+### Basic info about domain names
+
+- Domain names usually require a *very* small year fee to keep
+ registered, usually around \$12 for most generic TLDs. There are
+ some \"specialty\" TLDs that are more expensive, but `.com`, `.xyz`
+ and other basic TLDs are that cheap.
+- Once you own a domain, it is yours as long as you pay the yearly
+ fee, but you can also sell it to someone for however much you want.
+- Domain names do not hold your data or your website, instead, you add
+ \"DNS settings\" that direct people connecting to your domain to
+ your IP address. The purpose of a domain name is so that people
+ don\'t have to remember your IP address to find your website!
+
+### Looking for domain names
+
+Let\'s go to [Epik\'s site](https://www.epik.com/?affid=we2ro7sa6) and
+you can search for domain names.
+
+You can look for whatever domain name you want. Domains that are already
+bought and owned by someone else might have the option to \"Backorder,\"
+but it\'s always best to get one that is unowned, like these:
+
+{{< img alt="Searching for a domain name" src="/pix/domain-search.png" link="/pix/domain-search.png" >}}
+
+Note the differences in prices. Some \"specialty\" TLDs like `.game` and
+`.io` charge a much larger fee, although you might want one. Some
+domains above, like `.xyz` and `.org` have reduced prices for the first
+year.
+
+Choose the domain you want and buy it. These `.xyz` domains are a steal
+now on sale.
+
+{{< img alt="Buying a domain name" src="/pix/domain-cart.png" link="/pix/domain-cart.png" >}}
+
+That\'s all you have to do to own a domain name! As you register a
+domain, you can also setup an automatic payment to pay your fee yearly
+to keep your domain. Easy as pie.
+
+Now we will get a server to host your website on.
diff --git a/content/basic/nginx.md b/content/basic/nginx.md
new file mode 100644
index 0000000..fb8f15a
--- /dev/null
+++ b/content/basic/nginx.md
@@ -0,0 +1,212 @@
+---
+title: "Setting Up an NginX Webserver"
+date: 2021-07-10
+tags: ['basic']
+---
+At this point, we should have a domain name and a server and the domain
+name should direct to the IP address of the server with DNS records. As
+I said in previous articles, the instructions I will give will be for
+**Debian**. In this article, other distributions might work a little
+differently.
+
+## Logging in to the server
+
+We first want to log into our VPS to get a command prompt where we can
+set up the web server. I am assuming you are using either MacOS or
+GNU/Linux and you know how to open a terminal. On Windows, you can also
+use either PuTTY or the Windows Subsystem for Linux.
+
+Now on Vultr\'s site, you can click on your VPS and you will see that
+there is an area that shows you the password for your server at the
+bottom here.
+
+{{< img alt="Find your password" src="/pix/nginx-password.png" link="/pix/nginx-password.png" >}}
+
+Now pull up a terminal and type:
+
+```sh
+ssh root@example.org
+```
+
+This command will attempt to log into your server. It should prompt you
+for your password, and you can just copy or type in the password from
+Vultr\'s site.
+
+If you get an error here, you might not have done your [DNS
+settings](dns.html) right. Double check those. Note you can also replace
+the `example.org` with your IP address, but you\'ll want to fix your DNS
+settings soon.
+
+## Installing the Webserver: Nginx
+
+If the program runs without an error, `ssh` has now logged you into your
+server. Let\'s start by running the following commands.
+
+```sh
+apt update
+apt upgrade
+apt install nginx
+```
+
+The first command checks for packages that can be updated and the second
+command installs any updates.
+
+The third command installs `nginx` (pronounced Engine-X) which is the
+web server we\'ll be using, along with some other programs.
+
+### Our nginx configuration file
+
+`nginx` is your webserver. You can make a little website or page, put it
+on your VPS and then tell `nginx` where it is and how to host it on the
+internet. It\'s simple. Let\'s do it.
+
+`nginx` configuration files are in `/etc/nginx/`. The two main
+subdirectories in there (on Debian and similar OSes) are
+`/etc/nginx/sites-available` and `/etc/nginx/sites-enabled`. The names
+are descriptive. The idea is that you can make a site configuration file
+in `sites-available` and when it\'s all ready, you make a link/shortcut
+to it in `sites-enabled` which will activate it.
+
+First, let\'s create the settings for our website. You can copy and
+paste (with required changes) but I will also explain what the lines do.
+
+Create a file in `/etc/nginx/sites-available` by doing this:
+
+```sh
+nano /etc/nginx/sites-available/mywebsite
+```
+
+Note that \"nano\" is a command line text editor. You will now be able
+to create and edit this file. By saving, this file will now appear. Note
+also I name the file `mywebsite`, but you can name it whatever you\'d
+like.
+
+I\'m going to add the following content to the file. The content **like
+this** will be different depending on what you want to call your site.
+
+```nginx
+server {
+ listen 80 ;
+ listen [::]:80 ;
+ server_name landchad.net ;
+ root /var/www/landchad ;
+ index index.html index.htm index.nginx-debian.html ;
+ location / {
+ try_files $uri $uri/ =404 ;
+ }
+}
+```
+
+#### Explanation of those settings
+
+The `listen` lines tell `nginx` to listen for connections on both IPv4
+and IPv6.
+
+The `server_name` is the website that we are looking for. By putting
+`landchad.net` here, that means whenever someone connects to this server
+and is looking for that address, they will be directed to the content in
+this block.
+
+`root` specifies the directory we\'re going to put our website files in.
+This can theoretically be wherever, but it is conventional to have them
+in `/var/www/`. Name the directory in that whatever you want.
+
+`index` determine what the \"default\" file is; normally when you go to
+a website, say `landchad.net`, you are actually going to a file at
+`landchad.net/index.html`. That\'s all that is. Note that that this in
+concert with the line above mean that `/var/www/landchad/index.html`, a
+file on our computer that we\'ll create will be the main page of our
+website.
+
+Lastly, the `location` block is really just telling the server how to
+look up files, otherwise throw a 404 error. Location settings are very
+powerful, but this is all we need them for now.
+
+### Create the directory and index for the site
+
+We\'ll actually start making a \"real\" website later, but let\'s go
+ahead and create a little page that will appear on when someone looks up
+the domain.
+
+```sh
+mkdir /var/www/landchad
+```
+
+Now let\'s create and index file inside of that directory which will
+appear when the website is accessed:
+
+```sh
+nano /var/www/landchad/index.html
+```
+
+I\'ll add the following basic content, but you can add whatever you
+want. This will appear on your website.
+
+```html
+<!DOCTYPE html>
+<h1>My website!</h1>
+<p>This is my website. Thanks for stopping by!</p>
+<p>Now my website is live!</p>
+```
+
+### Enable the site {#enable}
+
+Once you save that file, we can enable it making a link to it in the
+`sites-enabled` directory:
+
+```sh
+ln -s /etc/nginx/sites-available/mywebsite /etc/nginx/sites-enabled
+```
+
+Now we can just `reload` or `restart` to make `nginx` service the new
+configuration:
+
+```sh
+systemctl reload nginx
+```
+
+## The Firewall {#firewall}
+
+Vultr and some other VPS automatically install and enable `ufw`, a
+firewall program. This will block basically everything by default, so we
+have to change that. If you don\'t have `ufw` installed, you can skip
+this section.
+
+We must open up at least ports 80 and 443 as below:
+
+```sh
+ufw allow 80
+ufw allow 443
+```
+
+Port 80 is the canonical webserver port, while 443 is the port used for
+encrypted connections. We will certainly need that for the next page.
+
+<aside>
+
+As you add more services to your website, they might need you to open more ports, but that will be mentioned on individual articles.
+(It should be noted that some local services only running for other services on your machine, so you *don't* need to open ports for every process running locally, *only* those that directly interact with the internet, although it's common to run those through NginX for simplicity and security.)
+
+</aside>
+
+## Nginx security hint
+
+By default, Nginx and most other webservers automatically show their
+version number on error pages. It\'s a good idea to disable this from
+happening because if an exploit comes out for your server software,
+someone could exploit it. Open the main Nginx config file
+`/etc/nginx/nginx.conf` and find the line `# server_tokens off;`.
+Uncomment it, and reload Nginx.
+
+Remember to [keep your server software up to
+date](maintenance.html#update) to get the latest security fixes!
+
+## We now have running website!
+
+At this point you can now type in your website in your browser and this
+webpage will appear!
+
+{{< img alt="The webpage as it appears." src="/pix/nginx-website.png" link="/pix/nginx-website.png" >}}
+
+Note the \"Not secure\" notification. The next brief step is securing
+encrypted connections to your website.
diff --git a/content/basic/server.md b/content/basic/server.md
new file mode 100644
index 0000000..6b6e233
--- /dev/null
+++ b/content/basic/server.md
@@ -0,0 +1,97 @@
+---
+title: "Get a Server"
+tags: ['basic']
+date: 2021-06-04
+---
+Once you have a [domain name](domain), you\'ll need a server to
+host all your website files on. In general, a server is just a computer
+that is constanly broadcasting some services on the internet.
+
+Servers connected to the internet can be extremely useful with or
+without proper websites attached to them. You can be your own website,
+email, file-sharing service and much more.
+
+## Getting a VPS
+
+A Virtual Personal Server (VPS) is a very cheap and easy way to get a
+web server. Without you having to buy expensive equipment. There are a
+lot of online businesses that have massive server farms with great
+internet connection and big power bills that allow you to rent a VPS in
+that farm for pocket change.
+
+A VPS usually costs \$5 a month. Sometimes slightly more, sometimes
+slightly less. That\'s a good price for some internet real-estate, but
+in truth, you can host a huge number of websites and services on a
+single VPS, so you get a lot more. I might have a dozen websites, an
+email server, a chat server and a file-sharing services on one VPS.
+
+The VPS provider that I\'ll be using for this guide is Vultr, since that
+is what I use. Vultr provides a free one-month \$100 credit to anyone
+who starts an account through [this referral link of
+mine](https://www.vultr.com/?ref=8384069-6G) so you can play around with
+their services with impunity.
+
+## Starting your server in two minutes or less
+
+[Start an account on Vultr](https://www.vultr.com/?ref=8384069-6G) and
+let\'s get started.
+
+Vultr (and other VPS providers) usually give you a choice in where and
+what exactly your VPS is.
+
+#### Server Location
+
+In general, it doesn\'t *hugely* matter what physical location you have
+your server in. You might theoretically want it close to where you or
+your audience might be, but if you host a server in Singapore for an
+American audience, they won\'t have to be waiting a perceptibly longer
+time to load the site.
+
+{{< img alt="Pick your servers's location" src="/pix/server-location.png" link="/pix/server-location.png" >}}
+
+**Some locations might have different abilities and plans than others.
+For example, in Vultr, their New York location has optional DDOS
+protection and also has some cheaper \$3.50 servers.**
+
+#### Operating System/Server Type
+
+{{< img alt="server type" src="/pix/server-type.png" link="/pix/server-type.png" >}}
+
+I especially recommend **Debian 10** for an operating system for your
+server. Debian is the \"classic\" server OS and as such, **I make my
+guides on this site for Debian 10**. If you use another OS, just know
+that your millage may vary in terms of you might need to change some
+instructions here minorly.
+
+#### Server size
+
+{{< img alt="server size" src="/pix/server-size.png" link="/pix/server-size.png" >}}
+
+You finally have a choice in how beefy a server you want. On Vultr, I
+recommend getting the cheapest option that is not IPv6 only.
+
+Web hosting and even moderately complicated sites do not use huge
+amounts of RAM or CPU power. If you start doing more intensive stuff
+than hosting some webpages and an email server and such, you can always
+bump up your plan on Vultr without data loss (it\'s not so easy to bump
+down).
+
+#### Additional features
+
+{{< img alt="additional features" src="/pix/server-features.png" link="/pix/server-features.png" >}}
+
+On Vultr, there are some final checkboxes you can select additional
+options. **You will want to check *Enable IPv6* and also *Block Storage
+Compatible*.**
+
+We will be setting up IPv6 because it\'s important for future-proofing
+your website as more of the web moves to the IPv6 protocol. Block
+storage is the ability (if you want) to later rent large storage disks
+to connect to your VPS if desired. You just might want that as an
+option, so it\'s worth activating now.
+
+### Done!
+
+Once you select those settings, your server will automatically be
+deployed. Momentarily, you will be able to see your server\'s IP
+addresses which will be used for the next brief step:
diff --git a/content/bitcoin.md b/content/bitcoin.md
new file mode 100644
index 0000000..221ff67
--- /dev/null
+++ b/content/bitcoin.md
@@ -0,0 +1,105 @@
+---
+title: "Getting a Bitcoin Wallet"
+date: 2020-06-28
+icon: "btc.svg"
+---
+Let\'s now get a Bitcoin wallet and become able to receive Bitcoin funds
+or donations.
+
+## Wallets
+
+One of the classical choices for a Bitcoin wallet is Electrum. Go to
+[https://electrum.org](https://electrum.org/#home) to download and
+install it, or if you are a Linux user, it is probably included in your
+distribution\'s package repository.
+
+### Mobile version?
+
+Note also that there are mobile/cell phone versions of Electrum for
+Android and iOS. I generally advise against using a wallet on a cell
+phone for security reasons, but if you would like, you can.
+
+If you are okay with a mobile wallet, I recommend getting [Cake
+Wallet](https://cakewallet.com/), which can use Electrum-style Bitcoin
+wallets, but also Monero and Litecoin.
+
+## Generating a Wallet
+
+Once you open Electrum (or Cake Wallet), you can choose to create a new
+wallet. Name it whatever you want and choose the \"Standard Wallet\"
+option.
+
+I will also note that if you are paranoid, it is perfectly possible to
+generate a wallet without connection to the internet.
+
+### Your Seed is your money.
+
+Now choose the \"Create a new seed\" option when creating the wallet.
+That will randomly produce a \"seed\" of 12 words.
+
+{{< img alt="bitcoin seed" src="/pix/bitcoin-01.png" link="/pix/bitcoin-01.png" >}}
+
+**These words are your money.** Once you are shown them, **immediately**
+write them down on physical paper, and you will be storing this
+somewhere it will not be lost or found. You can memorize these twelve
+words if you trust your memory.
+
+These twelve words unlock all of the funds/addresses you will have on
+this wallet. Whoever has your seed has the ability to spend your money.
+
+Note obviously that I have included a picture of a seed phrase above in
+this tutorial. I or anyone else would be stupid to ever send Bitcoin to
+the following addresses since the seed phrases are now public.
+
+Once you have written down your seed, click \"Next\" and Electrum will
+have you input that seed again to ensure you\'ve written it down.
+
+You will also be asked to supply a password. This password merely
+encrypts your wallet file on this computer so you don\'t have to retype
+your seed phrase each time you open Electrum. Note that anyone with your
+seed phrase can still obtain your funds. This password is only
+protection on your computer here.
+
+## Managing your Wallet
+
+Once your wallet is generated and opened you will be at the wallet page.
+First, I recommend opening the \"View\" menu and unhiding all the
+different tabs.
+
+{{< img alt="electrum options" src="/pix/bitcoin-02.png" link="/pix/bitcoin-02.png" >}}
+
+### Addresses
+
+The address tab contains all the many Bitcoin addresses generated by
+your seed phrase. In fact, as you use these up, the wallet will
+automatically add more.
+
+These addresses (which will all be generated with `bc1` at the
+beginning) can be used by others to send you Bitcoins. Someone can just
+copy-and-paste the address into their wallet to send you funds.
+
+{{< img alt="bitcoin addresses" src="/pix/bitcoin-03.png" link="/pix/bitcoin-03.png" >}}
+
+### Receive
+
+Click on the \"Receive\" tab and then click \"New Address.\" That will
+pick your first unused address which will appear on the right side. You
+could copy this from the \"Addresses\" tab, but this tab also generates
+a QR code which will appear to the right as well if you click on the
+\"QR Code\" subtab.
+
+{{< img alt="receive qr code" src="/pix/bitcoin-04.png" link="/pix/bitcoin-04.png" >}}
+
+#### What is the QR code for?
+
+In case you don\'t know, a QR code is a way of storing text information
+in a format that can be scanned by a phone. If someone has a wallet
+program on a phone, they can easily scan the QR code on another screen
+to avoid having to copy your address over or even worse, write it
+manually.
+
+### Let\'s receive donations on our website.
+
+Save the QR code and the wallet address it corresponds to (starting in
+`bc1`). Now simply put these on your website and anyone can send Bitcoin
+to them. Bitcoin users will know how to scan and use them.
diff --git a/content/btcpay.md b/content/btcpay.md
new file mode 100644
index 0000000..11ed7ed
--- /dev/null
+++ b/content/btcpay.md
@@ -0,0 +1,57 @@
+---
+title: "BTCPay"
+icon: 'btcpay.svg'
+tags: ['service']
+short_desc: "Host your own payment processor, powered by Bitcoin."
+draft: true
+---
+
+```sh
+apt install nginx python3-certbot-nginx tor postgresql postgresql-contrib iptables iptables-persistent
+```
+
+ *filter
+ :INPUT ACCEPT [0:0]
+ :FORWARD ACCEPT [0:0]
+ :OUTPUT ACCEPT [0:0]
+ -A INPUT -i lo -j ACCEPT
+ -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT # SSH
+ -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT # BTCPay HTTP
+ -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT # BTCPay HTTPS
+ -A INPUT -p tcp -m tcp --dport 8333 -j ACCEPT # Bitcoind P2P
+ -A INPUT -p tcp -m tcp --dport 9735 -j ACCEPT # Lightning P2P
+ -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
+ COMMIT
+
+`iptables-restore > iptables.txt` netfilter-persistent save
+
+ echo "ControlPort 9051
+ CookieAuthentication 1" >> /etc/tor/torrc
+
+certbot \--nginx -d pay.cedars.xyz \--agree-tos
+\--register-unsafely-without-email vim /etc/nginx/sites-available/btcpay
+
+## Building Bitcoin
+
+Now we can install the Bitcoin node and daemon software. For safety\'s
+sake, we will install it from source.
+
+First, we install the build dependencies:
+
+ apt install build-essential libtool autotools-dev automake pkg-config bsdmainutils python3 libevent-dev libboost-dev libboost-system-dev libboost-filesystem-dev libboost-test-dev git
+
+Now we can download the Bitcoin source code from the official
+repository:
+
+ git clone https://github.com/bitcoin/bitcoin
+ cd bitcoin
+
+Now, we compile, then install it. Compiling the software will take some
+time.
+
+ ./autogen.sh
+ ./configure
+ make
+ make install
+
+[[Next:\<++\>](%3C++%3E)]{.next}
diff --git a/content/calibre.md b/content/calibre.md
new file mode 100644
index 0000000..3e82b62
--- /dev/null
+++ b/content/calibre.md
@@ -0,0 +1,116 @@
+---
+title: "Calibre"
+date: 2021-08-03
+icon: "calibre.png"
+short_desc: 'A public or private digital library.'
+tags: ['service']
+---
+
+The Calibre library server is a great way to store your eBooks. It
+allows you to:
+
+- Share your books with others.
+- Easily transfer your books between devices and access them from
+ anywhere.
+
+## Installation
+
+Install the Calibre package. You might also want rsync to upload books.
+
+```sh
+apt install -y calibre rsync
+mkdir /opt/calibre
+```
+
+Either upload your existing library using `rsync`. For example to
+`/opt/calibre/`.
+
+```sh
+cd ~/Documents
+rsync -avuP your-library-dir root@example.org:/opt/calibre/
+```
+
+Or create a library and add a book to it:
+
+```sh
+cd /opt/calibre
+calibredb add book.epub --with-library your-library
+```
+
+For more information about the `calibredb` command see `man calibredb`.
+
+Add a new user to protect your server:
+
+```sh
+calibre-server --manage-users
+```
+
+## Creating a service
+
+Create a new file `/etc/systemd/system/calibre-server.service` and add
+the following:
+
+```systemd
+[Unit]
+Description=Calibre library server
+After=network.target
+
+[Service]
+Type=simple
+User=root
+Group=root
+ExecStart=/usr/bin/calibre-server --enable-auth --enable-local-write /opt/calibre/your_library --listen-on 127.0.0.1
+
+[Install]
+WantedBy=multi-user.target
+```
+
+You can change the port with the `--port` prefix. Additional information
+`man calibre-server`.
+
+Issue `systemctl daemon-reload` to apply the changes.
+
+Enable and start the service.
+
+```sh
+systemctl enable calibre-server
+systemctl start calibre-server
+```
+
+## A reverse proxy with Nginx
+
+Create a new file `/etc/nginx/sites-available/calibre` and enter the
+following:
+
+```nginx
+server {
+ listen 80;
+ client_max_body_size 64M; # to upload large books
+ server_name calibre.example.org ;
+
+ location / {
+ proxy_pass http://127.0.0.1:8080;
+ }
+}
+```
+
+Issue a Let\'s Encrypt certificate. [Detailed instructions and additional information](/certbot).
+
+```sh
+certbot --nginx
+```
+
+Now just go to **calibre.example.org**. The server will request an
+username and a password.
+
+{{< img src="/pix/calibre/calibre-1.png" alt="calibre" >}}
+
+
+After login you will see something like this.
+
+{{< img src="/pix/calibre/calibre-2.png" alt="calibre" >}}
+
+## Contribution
+
+Author: rflx -- [website](https://rflx.xyz) \-- XMR:
+`48T5XpHTXAZ5Nn8YCypA4aWn1ffQLHJkFGDArXQB6cmrP6cqLY72cu7CR2iq2MmL5Ndu3d47e5MKjGpL4prYgdrTCFAHD9c`
diff --git a/content/cgi.md b/content/cgi.md
new file mode 100644
index 0000000..5f293e9
--- /dev/null
+++ b/content/cgi.md
@@ -0,0 +1,210 @@
+---
+title: "Server-Side Scripting with CGI"
+date: 2021-07-25
+tags: ['server']
+---
+The basic website tutorial here describes how to set up a static website
+--- one that just serves HTML files saved on your server, and until you
+change something manually, the same content will be served each time a
+given page is requested. This is perfectly enough for most personal
+website needs. This is how blogs should be implemented, instead of
+relying on bloatware like WordPress!
+
+But sometimes you genuinely *do* need something more. You need your
+website to serve different contents depending on the time, on who the
+requester is, on the contents of a database, or maybe process user input
+from a form.
+
+## CGI
+
+CGI, or the Common Gateway Interface, is a specification to allow you,
+the server owner, to program your web server using pretty much any
+programming language you might know. The specification is almost as old
+as the Internet itself and for a long time CGI scripting was the primary
+method of creating dynamic websites.
+
+CGI is a very simple specification indeed. You write a script in your
+favorite language, the script receives input about the request in
+environment variables, and whatever you print to the standard output
+will be the response. Most likely, though, you will want to use a
+library for your language of choice that makes a lot of this
+request/response handling simpler (e.g. parsing query parameters for
+you, setting appropriate headers, etc.).
+
+### Limitations of CGI
+
+While in theory you could implement any sort of functionality with CGI
+scripts, it\'s going to get difficult managing a lot of separate scripts
+if they\'re supposed to be working in tandem to implement a dynamic
+website. If you want to build a full out web application, you\'d
+probably be better off learning a web framework than gluing together
+Perl scripts.
+
+That said, just as most of the web could be replaced with static
+websites, much of the remaining non-static web could be replaced with a
+few simple scripts, rather than bloated Ruby on Rails or Django
+applications.
+
+## Let\'s write a CGI script!
+
+We\'ll implement a simple example CGI script. I\'ll use Ruby for this
+tutorial, but you\'ll be able to follow along even if you don\'t know
+Ruby, just treat it as pseudocode then find a CGI library for your
+language.
+
+### The working example
+
+Our working example will be the Lazy Calculator. Yeah, you\'re probably
+tired of seeing calculator examples in every programming tutorial, but
+have you ever implemented one that takes the weekends off?
+
+Here\'s how it will work. When in a browser you submit a request to your
+website like
+
+```txt
+example.com/calculator.html?a=10&b=32
+```
+
+you will receive a page with the result of the addition of 10 and 32:
+42.
+
+*Unless* you send your request on a weekend. Then the website will
+respond with
+
+```txt
+I don't get paid to work on weekends! Come back Monday.
+```
+
+This example will show a few things that CGI scripts can do that you
+wouldn\'t have been able to get using just file hosting in your web
+server:
+
+- getting inputs from the user;
+- getting external information (here just the system time, but you
+ could imagine instead connecting to a database);
+- using the above to create dynamic output.
+
+### The code
+
+Here\'s an implementation of the lazy calculator as a Ruby CGI script:
+
+```ruby
+#!/bin/env ruby
+
+require 'cgi'
+require 'date'
+
+cgi = CGI.new
+today = Date::today
+
+a = cgi["a"].to_i
+b = cgi["b"].to_i
+
+if today.saturday? || today.sunday?
+ cgi.out do
+ "I don't get paid to work on weekends! Come back Monday."
+ end
+else
+ cgi.out do
+ (a + b).to_s
+ end
+end
+```
+
+Let\'s go through what\'s happening here.
+
+### The shebang line
+
+CGI works by pointing your web server to an executable program. A Ruby
+or Python script by itself is not immediately executable by a computer.
+But on Unix-like systems you can specify the program that will be able
+to execute your file in its first line if it starts with `#!` (known as
+the shebang; read more about it on
+[Wikipedia](https://en.wikipedia.org/wiki/Shebang_(Unix))).
+
+So if you\'re going to be using a scripting language, you\'ll probably
+need the appropriate shebang line at the top of your script. If you use
+a compiled language, you\'ll just point your web server to the compiled
+executable binary.
+
+### Query parameters
+
+The next interesting lines of code are where we set the variables `a`
+and `b`. Here we are getting user inputs from the request.
+
+In the example request we mentioned above
+(`example.com/calculator.html?a=10&b=32`), the part starting from the
+question mark, `?a=10&b=32`, is the *query string*. This is how users
+can submit parameters with their web requests. Usually these parameters
+are set by e.g. a form on your website, but in our simple example we\'ll
+be just manually manipulating the URL.
+
+The query string contains key-value pairs. The Ruby CGI library makes
+them available in the `CGI` object it provides. We just need to index it
+with the desired key, and we\'ll get the corresponding value.
+
+### Wrapping it up
+
+The remaining parts of the code should be pretty self-explanatory. We
+get today\'s date, check if it\'s a Saturday or a Sunday, and depending
+on that, we instruct the CGI library to output either the answer, or a
+\"come back later\" message.
+
+The Ruby library by default returns an HTML response, so we really
+should have wrapped our outputs in some `html`, `body`, etc. tags.
+Alternatively, we could have specified that the response is just plain
+text with
+
+```txt
+cgi.out 'text/plain' do
+```
+
+In general, your CGI library will probably have ways of specifying all
+sorts of HTTP response headers, like status code, content type, etc.
+
+## Making it work
+
+We have a CGI script, now let\'s point our web server to it.
+
+### Installing FastCGI
+
+If you\'re using Nginx, install `fcgiwrap`:
+
+```sh
+apt install fcgiwrap
+```
+
+This installs the necessary packages for Nginx to use FastCGI --- a
+layer between your web server and CGI script that allows for faster
+handling of scripts than if the web server had to handle it all by
+itself.
+
+Other web servers will probably have a similarly simple way of enabling
+FastCGI, or you can look into other methods for launching CGI scripts.
+
+### Nginx configuration
+
+In the configuration file for your website, add something like the
+following:
+
+```nginx
+location /calculator.html {
+ include fastcgi_params;
+ fastcgi_param SCRIPT_FILENAME /usr/local/bin/lazy-calculator.rb;
+ fastcgi_param QUERY_STRING $query_string;
+ fastcgi_pass unix:/run/fcgiwrap.socket;
+}
+```
+
+`fastcgi_param` directives specify various parameters for FastCGI.
+`SCRIPT_FILENAME` should point to your executable. For `QUERY_STRING`,
+we just copy Nginx\'s `$query_string` variable. You might want to pass
+other information to your CGI script as well, see for example [the
+Debian wiki](https://wiki.debian.org/nginx/FastCGI) for a more detailed
+example, including pointing to an entire directory of CGI scripts,
+rather than adding each one by hand to your web server config.
+
+## Contribution
+
+- Martin Chrzanowski \-- [website](https://m-chrzan.xyz),
+ [donate](https://m-chrzan.xyz/donate.html)
diff --git a/content/cgit.md b/content/cgit.md
new file mode 100644
index 0000000..70104a9
--- /dev/null
+++ b/content/cgit.md
@@ -0,0 +1,135 @@
+---
+title: "Cgit"
+date: 2021-09-14
+short_desc: 'A hyperfast web frontend for git repositories.'
+icon: 'cgit.svg'
+tags: ['service']
+---
+Once you have your server hosting your git repositories, you might want
+to allow others to browse your repositories on the web. Cgit is a Free
+Software that allows browsing git repositories through the web.
+
+Note that Cgit is a read-only frontend for Git repositories and doesn\'t
+have issues, pull requests or user management. If that\'s what you want,
+consider installing [Gitea](/gitea) instead.
+
+## Installing cgit and fcgiwrap
+
+### Install fcgiwrap
+
+NGINX doesn\'t have the capability to run CGI scripts by itself, it
+depends on an intermediate layer like fcgiwrap to run CGI scripts like
+cgit:
+
+```sh
+apt install fcgiwrap
+```
+
+And now we can install cgit itself with:
+
+```sh
+apt install cgit
+```
+
+## Setting up NGINX
+
+You should have an NGINX server running with a TLS certificate by now.
+Add the following configuration to your server to pass the requests to
+Cgit, while serving static files directly:
+
+```nginx
+server {
+ listen 443 ssl;
+ listen [::]:443 ssl;
+ ssl_certificate /etc/ssl/nginx/git.example.org.crt;
+ ssl_certificate_key /etc/ssl/nginx/git.example.org.key;
+ server_name git.example.org;
+
+ root /usr/share/cgit ;
+ try_files $uri @cgit ;
+
+ location @cgit {
+ include fastcgi_params;
+ fastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi;
+ fastcgi_param PATH_INFO $request_uri;
+ fastcgi_param QUERY_STRING $query_string;
+ fastcgi_pass unix:/run/fcgiwrap.socket;
+ }
+}
+```
+
+Then get NGINX to reload your configuration.
+
+## Configuring cgit
+
+You\'ve got cgit up and running now, but you\'ll probably see it without
+any style and without any repository. To change this, we need to
+configure Cgit to our liking, by editing `/etc/cgitrc`.
+
+```txt
+css=/cgit.css
+logo=/cgit.svg
+virtual-root=/
+
+# Title and description shown on top of each page
+root-title=Chad's git server
+root-desc=A web interface to LandChad's git repositories, powered by Cgit
+
+# The location where git repos are stored on the server
+scan-path=/srv/git/
+```
+
+This configuration assumes you followed the [git hosting guide](/git)
+and store your repositories on the `/srv/git/` directory.
+
+Cgit\'s configuration allows changing many settings, as documented on
+the cgitrc(5) manpage installed with Cgit.
+
+### Changing the displayed repository owner
+
+Cgit\'s main page shows each repo\'s owner, which is \"git\" in case you
+followed the git hosting guide, but you might want to change the name to
+yours. Cgit shows the owner\'s system name, so you need to modify the
+git user to give it your name:
+
+```sh
+usermod -c "Your Name" git
+```
+
+### Changing the repository description
+
+Navigate to your bare repository on the server and edit the
+`description` file inside it
+
+### Displaying the repository idle time
+
+To do this, we need to create a post-receive hook for each repository
+that updates the file cgit uses to determine the idle time. Inside your
+repository, create a file `hooks/post-receive` and add the following
+contents:
+
+```sh
+#!/bin/sh
+
+agefile="$(git rev-parse --git-dir)"/info/web/last-modified
+
+mkdir -p "$(dirname "$agefile")" &&
+git for-each-ref \
+ --sort=-authordate --count=1 \
+ --format='%(authordate:iso8601)' \
+ >"$agefile"
+```
+
+And give it execution permissions with:
+
+```sh
+chmod +x hooks/post-receive
+```
+
+Next time you push to that repository, the idle time should reset and
+show the correct value.
+
+## Contribution
+
+- Ariel Costas -- [website](https://costas.dev),
+ [donations](https://costas.dev/donations/)
diff --git a/content/coturn.md b/content/coturn.md
new file mode 100644
index 0000000..5dd60b3
--- /dev/null
+++ b/content/coturn.md
@@ -0,0 +1,111 @@
+---
+title: "Coturn"
+date: 2022-03-29
+short_desc: 'A STUN and TURN server that allows users to perform WebRTC calls while being behind NATs.'
+icon: "webrtc.svg"
+img: "webrtc.svg"
+tags: ['service']
+---
+
+[Coturn](https://github.com/coturn/coturn) is a libre **STUN** and
+**TURN** server software that allows users of chat protocols (Such as
+[XMPP](/prosody) and [Matrix](/matrix)) to perform WebRTC **voice
+and video calls** despite them being behind NATs.
+
+Almost every self-hosted voice and video conferencing program (such as
+[Jitsi](/jitsi) and [Nextcloud\'s](/nextcloud) Talk app) will
+**require** Coturn or some other equivalent turnserver to function
+properly.
+
+## Installation
+
+Coturn is available in the Debian repositories:
+
+```sh
+apt install coturn
+```
+
+## Configuration
+
+### Base configuration
+
+Coturn\'s configuration file is `/etc/turnserver.conf`. There are a few
+aspects that need to be changed in order to get a fully-functioning
+turnserver.
+
+Here is an example of some sane defaults:
+
+```md
+server-name=turn.example.org
+realm=turn.example.org
+listening-ip=your_public_ip
+
+listening-port=3478
+min-port=10000
+max-port=20000
+
+## The "verbose" option is useful for debugging issues
+verbose
+```
+
+### Authentication
+
+There are two options for authentication on a turnserver:
+
+1. **Usernames** and **passwords,**
+2. or **authentication secrets.**
+
+Depending on what self-hosted service is being used in conjunction with
+Coturn, you may need one or the other of these two options.
+
+#### Usernames and Passwords
+
+To utilize username and password authentication with Coturn, add the
+following configuration in `turnserver.conf`:
+
+```txt
+lt-cred-mech
+user=username:password
+```
+
+#### Authentication Secrets
+
+To utilize authentication secrets with Coturn, add the following
+configuration in `turnserver.conf`:
+
+```txt
+use-auth-secret
+static-auth-secret=your_auth_secret
+```
+
+## TURNS (TLS Encryption)
+
+Some self-hosted services (such as Matrix and XMPP) may support the use
+of **TURNS:** An encrypted version of TURN, which allows for WebRTC
+connections to be established with the use of an encrypted TLS tunnel,
+just like HTTPS allows for encrypted viewing of websites.
+
+To utilize TURNS, certificates need to be declared for
+**turn.example.org** in `turnserver.conf`:
+
+```txt
+cert=/etc/letsencrypt/live/turn.example.org/fullchain.pem
+pkey=/etc/letsencrypt/live/turn.example.org/privkey.pem
+```
+
+## Starting Coturn
+
+After all configuration changes are complete, Coturn can be started with
+its systemd daemon:
+
+```sh
+systemctl restart coturn
+```
+
+Congratulations! You\'ve successfully setup a Coturn server!
+
+------------------------------------------------------------------------
+
+*Written by [Denshi.](https://denshi.org) Donate Monero
+[here](https://denshi.org/donate.html)
+[\[QR\]](https://denshi.org/images/monero.jpg)*
diff --git a/content/cron.md b/content/cron.md
new file mode 100644
index 0000000..7ca3c10
--- /dev/null
+++ b/content/cron.md
@@ -0,0 +1,173 @@
+---
+title: "Cronjobs"
+date: 2020-07-01
+tags: ['server']
+---
+
+Cron is a service that lets you run scheduled tasks on a computer. These tasks
+are called **cronjobs.** If you have already followed the initial course you
+will have already used cron when you set up Certbot, but we'll explain how they work generally here.
+
+## What tasks would I want to schedule?
+
+You can schedule anything! Some examples of what you might have done
+already include:
+
+- `updatedb` to update your `locate` database to let you quicking search for files
+- `certbot` to update renewing of your https certs
+
+Some tasks that you might *want* to schedule may include:
+
+- Package updates - if you really just want to leave your server alone
+ you can automated updating packages on your server
+- Backups - you may want to backup certain files every day and some
+ every week, this is possible with cron
+
+And many more, anything you can do can be turned into a cronjob.
+
+## Basic Cronjobs
+
+This the preferred method for personal tasks and scripts; it\'s also the
+easiest to get started with. Run the command `crontab -e` to access your
+user\'s crontab
+
+Once you have figured out the command you want to run you need to figure
+out how often you want to run it and when. I am going to schedule my
+system updates once a week on at 3:30 AM on Mondays.
+
+We now have to convert this time (Every Monday at 3:30 AM) into a cron
+time. Cron uses a simple but effective way of scheduling when to run
+things.
+
+Crontab expressions look like this `* * * * * command-to-run` The five
+elements before the command tell when the command is supposed to be run
+automatically.
+
+So for our Monday at 3:30 AM job we would do the following:
+
+```txt
+ .---------------- minute (0 - 59)
+ | .------------- hour (0 - 23)
+ | | .---------- day of month (1 - 31)
+ | | | .------- month (1 - 12)
+ | | | | .---- day of week (0 - 6)
+ | | | | |
+ * * * * *
+30 3 * * 1 apt -y update && apt -y upgrade
+```
+
+### Some notes
+
+- On the day of the week option, Sunday is 0 and counting up from
+ there, Saturday will be 6.
+- `*` designates \"everything\". Our command above has a `*` in the
+ day of month and month columns. This means it will run regardless of
+ the day of the month or month.
+- The hour option uses 24 hour time. 3 = 3AM, while use 15 for 3PM.
+
+### More examples
+
+Let\'s add another job, our backup job (for the purposes of this our
+backup command is just called `backup`). We want to run `backup` every
+evening at 11PM. Once we work out the timings for this we can add the to
+the same file as the above by running `crontab -e` This would mean our
+full crontab would look like this:
+
+```txt
+0 23 * * * backup
+```
+
+### Consecutive times
+
+Suppose we want a command to run every weekday. We know we can put `1`
+(Monday), but we can also use `1-5` to signify from day 1 (Monday) to
+day 5 (Friday).
+
+```txt
+0 6 * * 1-5 echo "Wakey, wakey, wagie!" >> /home/wagie/alarm
+```
+
+The above `echo` command runs every Monday through Friday at 6:00AM.
+
+### Non-consecutive times
+
+We can also randomly specify non-consecutive arguments with a comma.
+Suppose you have a script you want to run at the midday of the 1st,
+15th, and 20th day of every month. You can specify that by putting
+`1,15,20` for the day of the month argument:
+
+```txt
+0 12 1,15,20 * * /usr/bin/pay_bills_script
+```
+
+### \"Every X minutes/days/months\"
+
+We can also easily run a command every several minutes or months,
+without specifying the specific times:
+
+```txt
+*/15 * * * * updatedb
+```
+
+This cronjob will run the `updatedb` command every 15 minutes.
+
+### Beware of this Rookie Mistake Though\...
+
+Suppose you want to run a script once every other month. You might be
+*tempted* write this:
+
+```txt
+* * * */2 *
+```
+
+That might *feel right*, but this script *will be running once every
+minute during that every other month*. You should specify the first two
+arguments, because with `*` it will be running every minute and hour!
+
+```txt
+0 0 1 */2 *
+```
+
+This makes the command run *only* at 0:00 (12:00AM) on the first day of
+every two months, which is what we really want.
+
+Consult the website [crontab.guru](https://crontab.guru) for an
+intuitive and interactive tester of cronjobs.
+
+## User vs. Root Cronjobs
+
+It is important to note that user accounts all have different cronjobs.
+If you have a user account `chad` and edit his crontab with
+`crontab -e`, the commands you add will be run as the `chad` user, not
+`root` or anyone else.
+
+Bear in mind that if you need root access to run a particular command,
+you will usually want to add it as root.
+
+## System-wide cron directories
+
+`crontab -e` is the typical interface for adding cronjobs, but it\'s
+important to at least know that system-wide jobs are often stored in the
+file directory. Some programs which need cronjobs will automatically
+install them in the following way.
+
+Run the command `ls /etc/cron*` you should see a list of directories and
+there contents. The directories should be something like the below:
+
+- /etc/cron.d *This is a crontab like the ones that you create with*
+ `crontab -e`
+- /etc/cron.hourly
+- /etc/cron.daily
+- /etc/cron.weekly
+- /etc/cron.monthly
+
+The directories cron.{hourly,daily,weekly,monthly} are where you can put
+**scripts** to run at those times. You don\'t put normal cron entries
+here. I prefer to use these directories for system wide jobs that don\'t
+relate to an individual user.
+
+## Contribution
+
+- Mark McNally \-- [website](https://mark.mcnally.je),
+ [Youtube](https://www.youtube.com/channel/UCMiInY8BhSUtCarO6uu6i_g)
+- Edits and examples by Luke
diff --git a/content/ejabberd.md b/content/ejabberd.md
new file mode 100644
index 0000000..0a7f3a8
--- /dev/null
+++ b/content/ejabberd.md
@@ -0,0 +1,259 @@
+---
+title: "ejabberd"
+date: 2022-03-29
+icon: 'ejabberd.png'
+tags: ['service']
+short_desc: "A chat server based on XMPP."
+---
+
+[Ejabberd](https://ejabberd.im) is a server for the XMPP protocol
+written in Erlang. It\'s easier to configure and setup than
+[Prosody](/prosody) due to having most of its modules built-in and
+pre-configured by default.
+
+## Prerequisites
+
+### Subdomains
+
+Ejabberd presumes that you have already created all the **required and
+optional subdomains** for its operation prior to running it.
+
+Depending on the usecase, you may need any or all of the following
+domains for XMPP functionality:
+
+- **example.org** - Your XMPP hostname
+- **conference.example.org** - For Multi User Chats (MUCs)
+- **upload.example.org** - For file upload support
+- **proxy.example.org** - For SOCKS5 proxy support
+- **pubsub.example.org** - For publish-subscribe support
+
+This guide will assume **all these subdomains** have been created.
+
+## Installation
+
+Ejabberd is available in the Debian repositories:
+
+```sh
+apt install ejabberd
+```
+
+## Configuration
+
+The ejabberd server is configured in `/etc/ejabberd/ejabberd.yml`.
+Changes are only applied by restarting the ejabberd daemon in systemd:
+
+```sh
+systemctl restart ejabberd
+```
+
+### Hostnames
+
+The **XMPP hostname** is specified in the `hosts` section of
+`ejabberd.yml`:
+
+```yml
+hosts:
+ - example.org
+```
+
+### Certificates
+
+Unlike [Prosody,](https://prosody.im) ejabberd doesn\'t come equipped
+with a script that can automatically copy over the relevant certificates
+to a directory where the ejabberd user can read them.
+
+One way of organizing certificates for ejabberd is to have them stored
+in `/etc/ejabberd/certs`, with each domain having a separate directory
+for both the fullchain cert and private key.
+
+Using certbot, this process can be easily automated with these commands:
+
+```sh
+$DOMAIN=subdomain.example.org
+certbot --nginx -d $DOMAIN certonly; mkdir /etc/ejabberd/certs/$DOMAIN
+cp /etc/letsencrypt/live/$DOMAIN/fullchain.pem /etc/ejabberd/certs/$DOMAIN
+cp /etc/letsencrypt/live/$DOMAIN/privkey.pem /etc/ejabberd/certs/$DOMAIN
+```
+
+This should be ran with your XMPP hostname **(example.org)** and
+repeated for all your desired subdomains.
+
+To enable the use of all these certificates in ejabberd, the following
+configuration is necessary:
+
+```yml
+certfiles:
+ - "/etc/ejabberd/certs/*/*.pem"
+```
+
+### Admin User
+
+The **admin user** can be specified in `ejabberd.yml` under the `acl`
+section:
+
+```yml
+acl:
+ admin:
+ user: admin
+```
+
+This would make **admin@example.org** the user with administrator
+privileges.
+
+### Message Archives
+
+The ejabberd server supports keeping archives of messages through its
+`mod_mam` module. This can be enabled by uncommenting the following
+lines:
+
+```yml
+mod_mam:
+ assume_mam_usage: true
+ default: always
+```
+
+## Database
+
+### Why use a database?
+
+In the `mod_mam` section of the ejabberd config file, the following
+message is in comments:
+
+```yml
+mod_mam:
+ ## Mnesia is limited to 2GB, better to use an SQL backend
+ ## For small servers SQLite is a good fit and is very easy
+ ## to configure. Uncomment this when you have SQL configured:
+ ## db_type: sql
+```
+
+As these comments imply, an **SQL backend** is strongly recommended if
+you wish to use your ejabberd server for anything more than just
+testing. Ejabberd supports **MySQL, SQLite** and **PostgreSQL.**
+
+While all of those are suitable choices, the best database system to use
+is PostgreSQL. It\'s the same database backend used by
+[PeerTube](/peertube) and [Matrix](/matrix), making it the most
+convenient option if you\'re already running those too.
+
+### Installing PostgreSQL
+
+PostgreSQL is available in the Debian repositories:
+
+```sh
+apt install postgresql
+```
+
+Start the PostgreSQL daemon to begin using it:
+
+```sh
+systemctl start postgresql
+```
+
+### Creating the Database
+
+To create the database, first create a PostgreSQL user for ejabberd:
+
+```sh
+su -c "createuser --pwprompt ejabberd" postgres
+```
+
+Then, create the database and make `ejabberd` its owner:
+
+```sh
+su -c "psql -c 'CREATE DATABASE ejabberd OWNER ejabberd;'" postgres
+```
+
+### Importing Database Scheme
+
+Ejabberd doesn\'t create the database scheme by default; It has to be
+imported into the database before use.
+
+```sh
+su -c "curl -s https://raw.githubusercontent.com/processone/ejabberd/master/sql/pg.sql | psql ejabberd" postgres
+```
+
+### Configuring ejabberd to use PostgreSQL
+
+Finally, add the following configuration to `ejabberd.yml`:
+
+```yml
+sql_type: pgsql
+sql_server: "localhost"
+sql_database: "ejabberd"
+sql_username: "ejabberd"
+sql_password: "psql_password"
+```
+
+Once you\'ve ensured your database name, username and password are all
+correct, enable SQL storage for `mod_mam`:
+
+```yml
+mod_mam:
+ ## (Other parameters)
+ db_type: sql
+```
+
+## Using ejabberd
+
+### Registering the Admin User
+
+To begin using ejabberd, firstly start the ejabberd daemon:
+
+```sh
+systemctl restart ejabberd
+```
+
+Then, using `ejabberdctl` as the ejabberd user, register the admin user
+which is set in `ejabberd.yml`:
+
+```sh
+su -c "ejabberdctl register admin example.org password" ejabberd
+```
+
+This will create the user **admin@example.org.**
+
+### Using the Web Interface
+
+By default, ejabberd has a web interface accessible from
+**http://example.org:5280/admin**. When accessing this interface, you
+will be prompted for the admin credentials:
+
+{{< img src="/pix/ejabberd-login.jpg" >}}
+
+After signing in with the admin credentials, you will be able to manage
+your ejabberd server from this web interface:
+
+{{< img src="/pix/ejabberd-admin.jpg" >}}
+
+## TURN & STUN for Calls
+
+Ejabberd supports the **TURN** and **STUN** protocols to allow internet
+users behind NATs to perform voice and video calls with other XMPP
+users.
+
+Firstly, setup a TURN and STUN server with [Coturn,](/coturn) using
+an **authentication secret.**
+
+Then, edit `mod_stun_disco` to contain the appropriate information for
+your turnserver:
+
+```yml
+ mod_stun_disco:
+ secret: "your_auth_secret"
+ services:
+ -
+ host: turn.example.org
+ type: stun
+ -
+ host: turn.example.org
+ type: turn
+```
+
+And with that, you\'ve successfully setup your ejabberd XMPP server!
+
+------------------------------------------------------------------------
+
+*Written by [Denshi.](https://denshi.org) Donate Monero
+[here](https://denshi.org/donate.html)
+[\[QR\]](https://denshi.org/images/monero.jpg)*
diff --git a/content/federation.md b/content/federation.md
new file mode 100644
index 0000000..770739c
--- /dev/null
+++ b/content/federation.md
@@ -0,0 +1,57 @@
+---
+title: "Federation"
+draft: true
+tags: ['concepts','activity-pub']
+---
+The internet was supposed to be a place where everyone was an internet
+LandChad. Everyone had their own website and email and own services.
+Obviously, this site is all about getting back to that ideal.
+
+That\'s why it\'s important to understand the concept of
+<dfn>Federation</dfn> in technology. It\'s the idea that instead of one
+central \"node\" or site that everyone uses, like Facebook, Twitter,
+Insta, R\*ddit, people can run their own sites that can nonetheless
+*interact* with othersites as easily as if they were the same.
+
+You already know one federated technology: email. There is no one site
+for email, but many sites, and all people on all those sites can use
+email to talk to one another. You can get censored on Facebook. You
+can\'t get censored on \"email.\" You could have a Gmail account
+deleted, but you are not blocked out of the system, as you can go to any
+number of sites and get a new account or [make your own server](/email) and you can still talk to all your friends via
+email.
+
+## \"Federated\" Social Media
+
+The idea of Federated Social Media is using that principle used in
+email, but for other things, like chatting or social media.
+
+Here\'s an example. There is some software [you can install on your
+server](/pleroma) called [Pleroma](https://pleroma.social/). It can
+be installed on your site just like a web or email server, but what it
+does is creates a Twitter-like microblogging site. You can then have
+your friends join and use it just like you use Twitter, with you as the
+admin and deciding policy and you can even format and decorate the site
+how you want.
+
+### It gets even better\...
+
+**But here is the clincher.** Federated social media like Pleroma can
+interact with other Pleroma servers on the internet in the same way that
+Gmail\'s servers can send messages to any other email server. So you
+might have 2 people on your Pleroma site, but you can interact with the
+many thousands of other Pleroma sites.
+
+There is seamless interaction. You can view, like, share and respond to
+their posts as if they were part of your own site.
+
+### And it gets even betterer\...
+
+Pleroma is based on a protocol called [Activity
+Pub](https://activitypub.rocks/). This is also used by other software
+like [PeerTube](https://joinpeertube.org/) (which is a self-hosted
+YouTube-equivalent), [Friendica](https://friendi.ca/) (Facebook
+equivalent).
+
+Accounts on *all* of these platforms can view, interact with and participate with accounts on other platforms.
+You can do the equivalent of posting a comment on a "YouTube" video from your "Twitter" account.
diff --git a/content/fosspay.md b/content/fosspay.md
new file mode 100644
index 0000000..f7e3ae9
--- /dev/null
+++ b/content/fosspay.md
@@ -0,0 +1,183 @@
+---
+title: "Fosspay"
+tags: ['service']
+icon: 'devault.jpg'
+short_desc: "A self-hosted payment and donation gateway interfaced with Stripe."
+date: 2022-06-30
+---
+
+[Fosspay](https://sr.ht/~sircmpwn/fosspay/) is a free-software web frontend for receiving donations and
+subscriptions, similar to Patreon or Liberapay, but which can be hosted
+on your own server. It can also interface with Patreon or Github
+Sponsors to aggregate all your donations.
+
+## Stripe Setup
+
+Fosspay uses [Stripe](https://stripe.com) as a payment processor. You first must go to [their website](https://stripe.com) and create an account.
+
+Once you set everything up, you can go to [https://dashboard.stripe.com/account/apikeys](https://dashboard.stripe.com/account/apikeys) and get your "Publishable Key" and "Secret Key" which will be all you need to set up Fosspay.
+
+<aside>
+
+### Note on Free Software
+
+Stripe is perhaps the best way to transact in the legacy financial system
+online, but you are still not using free and privacy respecting software.
+Fosspay is an open source payment gateway, but it still connects to Stripe.
+The only way to transact value over the internet on all free software is
+[crypto-currency](/monero/).
+
+</aside>
+
+## Dependencies
+
+We will need git, postgres and the ability to make a python virtual
+environment:
+
+```sh
+apt install git python3-venv python3-dev postgresql libpq-dev
+```
+
+## Download and Installation
+
+We will download fosspay to `/var/www/fosspay/`. This directory will
+also serve as our virtual environement.
+
+```sh
+git clone https://git.sr.ht/~sircmpwn/fosspay /var/www/fosspay
+python3 -m venv /var/www/fosspay
+```
+
+Activate the python environment with the command below, then we will
+install the dependencies.
+
+```sh
+source /var/www/fosspay/bin/activate
+cd /var/www/fosspay
+pip install -r requirements.txt
+```
+
+Be sure you are still in `/var/www/fosspay`, then we will build the
+package and create the configuration file.
+
+```sh
+make
+cp config.ini.example config.ini
+```
+
+## Create a Database
+
+Fosspay uses a PostgreSQL database to store donation information, so
+let\'s create a database and user for it.
+
+First, become the `postgres` user and run the `psql` command:
+
+```sh
+su postgres
+psql
+```
+
+We will create a database named `fosspay` controled by a user named
+`fosspay` (also identified by a a password `fosspay`).
+
+```sql
+create database fosspay ;
+create user fosspay with encrypted password 'fosspay' ;
+grant all privileges on database fosspay to fosspay ;
+\q
+```
+
+Note that if you want to use a different username or password for
+whatever reason, change them in the command above, but also in the
+`connection-string` variable in the configuration file.
+
+## Configuration
+
+Now open up `/var/www/fosspay/config.ini` and we will set things up.
+Here are a list of things to edit.
+
+- `domain` should be set to `donate.example.org`, with your domain.
+- `protocol` can be set to `https`.
+- Get or create an email account to use as a mailer and add the account/server
+ information to the email settings.
+- Add your public and secret Stripe keys to the information.
+- Change the `connection-string` to
+ `postgresql://fosspay:fosspay@localhost/fosspay` as set up above.
+
+**An important note:** mail ports *must* be opened on the server you\'re using,
+or else Fosspay will silently fail to send mails when someone tries to donate
+or reset their password. You do not have to run a mail server on the same
+server as Fosspay, but either way, mail submission ports must be opened. This
+usually requires contacting your VPS provider and requesting it from them.
+Aside from this, any error in the email setup will cause Fosspay to crash
+silently.
+
+### Optional Integration with Patreon, Github, Liberapay
+
+Note that if you have a previous Patreon, Github Sponsors or Liberapay
+account, you can create an access token for Fosspay, so that you can
+display your income from those sources along side Fosspay monthly
+donations.
+
+For Liberapay, you only need to include your username. You must create a
+[Github access token](https://github.com/settings/tokens) with the
+\"user\" access to interface with it, and you have to add several
+[Patreon client
+parameters](https://www.patreon.com/portal/registration/register-clients)
+for it.
+
+## Nginx configuration
+
+Fosspay runs on port 5000, so we can have Nginx show the site. Create an
+Nginx configuration file modeled as below:
+
+```nginx
+server {
+ listen 80 ;
+ listen [::]:80 ;
+ server_name donate.example.org ;
+ location / {
+ proxy_pass http://localhost:5000 ;
+ }
+}
+```
+
+After that, [remember to get HTTPS for the subdomain!](/basic/certbot)
+HTTPS is absolutely required for using Stripe as a payment processor.
+
+## Systemd File
+
+We can now create a systemd service file for Fosspay. Create a file in
+`/etc/systemd/system/fosspay.service` as below:
+
+```systemd
+[Unit]
+Description=fosspay website
+Wants=network.target
+Wants=postgresql.target
+Before=network.target
+Before=postgresql.target
+[Service]
+Type=simple
+WorkingDirectory=/var/www/fosspay
+VIRTUAL_ENV=/var/www/fosspay
+Environment=PATH=$VIRTUAL_ENV/bin:$PATH
+ExecStart=/var/www/fosspay/bin/gunicorn app:app -b 127.0.0.1:5000
+ExecStop=/var/www/fosspay/bin/gunicorn
+[Install]
+WantedBy=multi-user.target
+```
+
+Note that for safety, we are running fosspay through `gunicorn` in our
+virtual environment.
+
+We can now run `systemctl start fosspay` to start the service, and it
+should appear at the URL you designated above.
+
+## Customizing the Page
+
+Within `/var/www/fosspay/templates`, there are various files that you
+can change to add text and other features to the page. The main file is
+`summary.html`, where you can add a description and other information
+that will appear. Restart the service after updating files to make
+changes live.
diff --git a/content/gemini.md b/content/gemini.md
new file mode 100644
index 0000000..dba5a1a
--- /dev/null
+++ b/content/gemini.md
@@ -0,0 +1,189 @@
+---
+title: "Gemini"
+date: 2021-07-01
+tags: ['server']
+short_desc: "A minimalist alternative to HTTP with a modern twist."
+---
+## What is Gemini? {#whatis}
+
+[Gemini](https://gemini.circumlunar.space) is a new
+internet protocol which is different from the HTTP and Gopher. It\'s
+much cleaner and has a growing community and audience of hackers.
+
+### Why use gemini protocol?
+
+- Gemini capsules (webpages of gemini) are lightweight, minimal, and
+ don\'t use many resources to operate.
+- It can run along with your websites. Gemini capsules use port 1965
+ by default. Your webserver can run at port 80 or 443 along with
+ gemini server at port 1965.
+- By exploring an alternative protocol, you can check different ways
+ to serve data and blogs.
+
+To access any gemini urls i.e. `gemini://example.org`, you can use any
+gemini client such as
+[amfora](https://github.com/makeworld-the-better-one/amfora),
+[lagrange](https://gmi.skyjake.fi/lagrange),
+[elpher](https://thelambdalab.xyz/elpher/), etc.
+
+## Instructions
+
+### Create a gemini user
+
+It is most secure and clean to have a separate `gemini` user, so let\'s
+create one:
+
+```sh
+useradd -m -s /bin/bash gemini
+```
+
+Now log in as `gemini` with the following command:
+
+```sh
+su -l gemini
+```
+
+To create and serve a gemini capsule, we need three basic steps:
+
+1. Content -- the webpages in our capsule
+2. TLS certificate -- Gemini requires encrypted connection.
+3. Gemini server -- the program that makes our capsule available
+ (similar to Nginx for HTTP)
+
+As the gemini user, we can create three different directories to
+simplify the process:
+
+```sh
+mkdir -p ~/gemini/{content,certificate,server}
+```
+
+### Content
+
+This will be the directory where your capsule files will be contained.
+Gemini uses text/gemini markup (in place of HTTP\'s equivalent HTML). It
+heavily borrows from Markdown. Similar to .html or .md, gemini uses .gmi
+as its extension.
+
+To create one gemini file, go inside the `content` directory and create
+one `index.gmi` file.
+
+```sh
+nano gemini/content/index.gmi
+```
+
+We can add the content we want in our Gemini capsule here:
+
+```yaml
+# This is Sample Gemini page
+## With header 1 and header 2
+And a short paragraph like this.
+=> /index.gmi Link to the same page
+```
+
+### TLS certificate
+
+Go to the `certificate` directory which we created earlier and generate
+a TLS certificate using OpenSSL.
+
+```sh
+cd ~/gemini/certificate/
+openssl req -new -subj "/CN=example.org" -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -days 3650 -nodes -out cert.pem -keyout key.pem
+```
+
+### Gemini server
+
+#### Download and prepare the server
+
+There are [many gemini server software choices
+available](https://gemini.circumlunar.space/software). We will use
+`agate` server for now. This is a simple gemini server written in Rust.
+
+It\'s a good idea to always get the most recent version, which you can
+see [on the agate releases
+page](https://github.com/mbrubeck/agate/releases). At the time of this
+writing, that is agate v3.1.0 which we will now download. We will
+download it to the `server` directory we made.
+
+```sh
+cd ~/gemini/server
+wget https://github.com/mbrubeck/agate/releases/download/v3.1.0/agate.x86_64-unknown-linux-gnu.gz
+```
+
+Unzip the gz, then rename and make it executable:
+
+```sh
+gunzip agate.x86_64-unknown-linux-gnu.gz
+mv agate.x86_64-unknown-linux-gnu agate-server
+chmod +x agate-server
+```
+
+#### Create a system service
+
+Now we need to create a systemd service to autostart and manage agate.
+The gemini user does not have permission to do this, so press `ctrl-d`
+to log out of the gemini user and return to root. As root, create the
+file below by opening it in your text editor (nano, vim, etc.):
+
+```sh
+nano /etc/systemd/system/agate.service
+```
+
+Add the following content to the file **customizing highlighted text**
+to your use.
+
+```systemd
+[Unit]
+Description=agate
+After=network.target
+
+[Service]
+User=gemini
+Type=simple
+ExecStart=/home/gemini/gemini/server/agate-server --content /home/gemini/gemini/content --certs /home/gemini/gemini/certificate/ --hostname example.org --lang en-US
+
+[Install]
+WantedBy=default.target
+```
+
+Now we are ready to run server. Enable and run agate server.
+
+```sh
+systemctl enable agate
+systemctl start agate
+```
+
+#### Firewall
+
+Lastly, if you have a firewall running, remember to open port 1965,
+which is the port number used by gemini:
+
+```sh
+ufw allow 1965
+```
+
+## Finalization
+
+Now your server should be running. If everything went okay, you can
+access your gemini capsule via any gemini client with a url like this:
+
+```txt
+gemini://example.org
+```
+
+Sample gemini site for reference:
+
+```txt
+gemini://gemini.circumlunar.space
+```
+
+Enjoy your first gemini capsule.
+
+For information about how to write in \"gemtext\" the markup language in
+Gemini, see this site:
+<https://gemini.circumlunar.space/docs/gemtext.gmi>. As you might guess,
+it also has an analogous gemini capsule here:
+gemini://gemini.circumlunar.space/docs/gemtext.gmi
+
+------------------------------------------------------------------------
+
+*Written by [nihar.page](https://nihar.page)*
diff --git a/content/git.md b/content/git.md
new file mode 100644
index 0000000..e186cd0
--- /dev/null
+++ b/content/git.md
@@ -0,0 +1,131 @@
+---
+title: "Git Server"
+date: 2020-07-01
+icon: 'git.svg'
+tags: ['service']
+short_desc: "Hosting your own basic git server."
+---
+
+Once you have your own VPS or other Internet-available server, you can
+start hosting your own git repositories. The goal of this tutorial is
+for you to go from
+
+```sh
+git clone github.com/...
+```
+
+to
+
+```sh
+git clone YourLandChadDomainName.xyz/...
+```
+
+so you can cultivate your own homegrown, grass-fed code, rather than
+relying on a centralized proprietary service like GitHub.
+
+## Installing git
+
+You most likely already have it installed on your server, but if not,
+run:
+
+```sh
+apt install git
+```
+
+We don\'t need any additional software, `git` itself ships with
+everything needed to host a remote repository!
+
+## Creating a git user
+
+To prevent exploiting your system, services should usually be run under another
+user that can only affect the relevant parts of the server. Let's create a user
+for git.
+
+```sh
+useradd -m git -d /var/git -s /bin/bash
+```
+
+The `git` user's home directory will be `/var/git` and we also set the default
+user shell as bash instead of sh for ease when on the command line.
+
+### Become the git user and create the directory
+
+If you\'re logged in to your server as root and have `git` installed,
+you can become the `git` user by executing
+
+```sh
+su -l git
+```
+
+The `-l` option should put us in `git`'s home directory, but you can `cd
+/var/git` otherwise.
+
+### Create the repo
+
+Now you can create the bare repository with
+
+```sh
+git init --bare my-repo.git
+```
+
+By convention, bare repository names end with \".git\". (A bare repository is
+just one without the file index, (i.e. the familiar browseable file structure).)
+
+Repeat the above command for any other repositories you want to host.
+
+## Syncing local repositories with your server
+
+### Set up SSH login for the git user
+
+Git uses SSH to connect to a server, and we will definitely want to use an SSH
+key pair that we authorized. This is not only most secure, but also easiest
+since we don't need to put in our password whenever we pull or push.
+
+There is a brief article [on setting up SSH keys](/sshkeys). We need to do
+exactly that, but for the `git` user, instead of the default `root` user. Note
+that if you want to upload your SSH key directly to the git user as in that
+tutorial, remember to run `passwd git` to give the git user a password so you
+can log in.
+
+If you've already set up password-less SSH log-ins for root (and disabled SSH
+password authentication), you can run the following commands as root, which
+will copy over your authorized key to the git user as well.
+
+```sh
+mkdir /var/git/.ssh # Create the required directory.
+cp ~/.ssh/authorized_keys /var/git/.ssh/ # Copy over the authorized key.
+chown git:git -R /var/git/.ssh # Make the created directory and contents to be owned by the git user.
+
+```
+
+### Syncing a new repository with your server
+
+How that we've set that up, we can push a repository we have on our computer to
+that newly created bare repo. First, on our local computer, we run a command like this:
+
+```sh
+git remote add origin git@example.org:my-repo.git
+```
+
+Note some of the things you will change:
+
+- `example.org`, obviously is a stand-in for your domain name.
+- `my-repo.git` is the name of the repository, but it is also the relative location of it. Since it is in the `git` user's home directory, we don't need anything else, but if you decide to put a git repository elsewhere---like in `/var/www/git/stuff.git`, you can provide that absolute file location instead.
+- `origin` is a unique name for your remote repository. Since "origin" is probably already used if you are using Github or another service, you'll want to change this to whatever you want. Could be `myserver` or `vps` or `own`, as long as it is unique.
+
+Once you run that command successfully to add a new remote repository, and also assuming you change `origin` to let's say the more unique `personal`, you can push your local git server as expected:
+
+```sh
+git push personal master
+```
+
+That's all a git server is! Very simple.
+
+If you want a minimalist front-end to a git server, follow our guide on [cgit](/cgit)!
+
+If you want a large and user-friendly Github-like site for your git projects, follow our guide on [Gitea](/gitea)!
+
+## Contribution
+
+- Martin Chrzanowski \-- [website](https://m-chrzan.xyz), [donate](https://m-chrzan.xyz/donate.html)
+- Edits and fixes by Luke.
diff --git a/content/gitea.md b/content/gitea.md
new file mode 100644
index 0000000..e09b6c0
--- /dev/null
+++ b/content/gitea.md
@@ -0,0 +1,161 @@
+---
+title: "Gitea"
+date: 2020-07-02
+icon: 'gitea.svg'
+tags: ['service']
+short_desc: "A fully-featured Github-like git website for serious software projects and communities."
+---
+
+Gitea allows you to self-host your git repositories similar to [bare
+repositories](/git), but comes with additional features that you might know
+from GitHub, such as issues, pull requests or multiple users. Its advantage
+over GitLab---another Free Software GitHub clone---is that it is much more
+lightweight and easier to setup.
+
+Head over to [gitea.com](https://gitea.com) to see what it looks like in
+practice.
+
+Although Gitea is lighter than Gitlab, if you have a VPS with only 512MB of
+RAM, you will probably have to upgrade. Gitea is more memory-intensive than
+having just a bare git repository. If you just want a minimalist browseable git
+server without issue tracking and pull requests, install [cgit](/cgit)
+instead.
+
+## Installing Gitea
+
+First install a few dependencies:
+
+```sh
+apt install curl sqlite3
+```
+
+Unfortunately, Gitea itself is not in the official Debian repos, so we
+will add a third-party repository for it.
+
+Add the repo\'s gpg key to apt\'s trusted keys:
+
+```sh
+curl -sL -o /etc/apt/trusted.gpg.d/morph027-gitea.asc https://packaging.gitlab.io/gitea/gpg.key
+```
+
+Then add the actual repository to apt:
+
+```sh
+echo "deb [arch=$(dpkg --print-architecture)] https://packaging.gitlab.io/gitea gitea main" > /etc/apt/sources.list.d/morph027-gitea.list
+```
+
+Now we can install Gitea:
+
+```sh
+apt update
+apt install gitea
+```
+
+Since apt automatically enables and starts the Gitea service, it should
+already be running on port `3000` on your server!
+
+## Setting up a Nginx reverse proxy
+
+You should know how to generate SSL certificates and use Nginx by now.
+Add this to your Nginx config to proxy requests made to your git
+subdomain to Gitea running on port 3000:
+
+```nginx
+server {
+ listen 443 ssl;
+ listen [::]:443 ssl;
+ ssl_certificate /etc/ssl/nginx/git.example.org.crt;
+ ssl_certificate_key /etc/ssl/nginx/git.example.org.key;
+ server_name git.example.org;
+ location / {
+ proxy_pass http://localhost:3000/; # The / is important!
+ proxy_redirect off;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ }
+}
+```
+
+
+And reload Nginx:
+
+```sh
+systemctl reload nginx
+```
+
+## Setting up Gitea
+
+If everything worked fine you should now see a setup screen when you go
+to your configured domain in the browser. The options should be pretty
+self-explanatory, it is only important to select SQLite3 and to replace
+the base url and SSH server domain with your own.
+
+Database Type:
+: SQLite3
+
+SSH Server Domain:
+: **git.example.org**
+
+Gitea Base URL:
+: **git.example.org**
+
+These and other settings can be changed in a configuration file later so
+don\'t worry about making wrong decisions right now.
+
+After clicking the install button you should now be able to log into
+your Gitea instance with the account you just created! Explore the
+settings for more things to do, such as setting up your SSH keys.
+
+If Gitea does not load fully and has random errors, it is possible that
+you need to increase your available memory on your VPS. This can usually
+be done on your VPS-provider\'s website without too much trouble.
+
+## A few extras
+
+### Automatically create a new repo on push
+
+This is an incredibly useful feature for me. Open up
+`/etc/gitea/app.ini` and add `DEFAULT_PUSH_CREATE_PRIVATE = true` to the
+`repository` section like so:
+
+```systemd
+[repository]
+ROOT = /var/lib/gitea/data/gitea-repositories
+DEFAULT_PUSH_CREATE_PRIVATE = true
+```
+
+If you now add a remote to a repository like this
+
+```sh
+git remote add origin 'ssh://gitea@git.example.org/username/coolproject.git'
+```
+
+and push, Gitea will automatically create a private `coolproject`
+repository in your account!
+
+### Change tab-width
+
+By default Gitea displays tabs 8 spaces wide, however I prefer 4 spaces.
+We can change this!
+
+```sh
+mkdir -p /var/lib/gitea/custom/templates/custom/
+```
+
+And write this into
+`/var/lib/gitea/custom/templates/custom/header.tmpl`:
+
+```css
+<style>
+.tab-size-8 {
+tab-size: 4 !important;
+-moz-tab-size: 4 !important;
+}
+</style>
+```
+
+## Contribution
+
+- [phire](https://phire.cc)
diff --git a/content/html.md b/content/html.md
new file mode 100644
index 0000000..3da7c53
--- /dev/null
+++ b/content/html.md
@@ -0,0 +1,143 @@
+---
+title: "Make a Simple Webpage"
+draft: true
+---
+We now have a webpage that\'s actually on the real-live internet!
+You\'ve already made it! Now the only issue is putting what you want on
+your website.
+
+In this little series, we\'ll overview the basics of HTML and CSS, the
+two important languages that will allow you to make a stylish multi-page
+website. We will start with HTML.
+
+## HTML
+
+HTML is the **h**yper**t**ext **m**arkup **l**anguage. It is the
+\"language\" that all webpages are written in so that all browsers can
+read and display them properly.
+
+A <dfn>markup language</dfn> is *not* the same as a programming language:
+Programming languages specify orders for a computer, while markup
+languages are ways of specifying the styling of text. Markup languages
+are necessary because computers run on mere text, not colors, sizes,
+headers and other styling things.
+
+Let\'s understand what HTML is. In [a previous article](/basic/nginx), we
+put this text in your website\'s `index.html`.
+
+### Paragraphs
+
+Note how this HTML file appears as a webpage:
+
++-----------------------------------+-----------------------------------+
+| <!DOCTYPE html> | ![The webpage as it |
+| <h1>My website!</h1> | appears.](pix/nginx-website.png) |
+| <p>This is my web | |
+| site. Thanks for stopping by!</p> | |
+| | |
+| <p>Now my website is live!</p> | |
++-----------------------------------+-----------------------------------+
+
+The content between the `<p>` and `</p>` tag(s) is formatted as
+different paragraphs. If you don\'t use these `<p>` tags, the text will
+not be formatted as separate paragraphs even if you write it as multiple
+lines. Observe if we add lines to the end of this file:
+
++-----------------------------------+-----------------------------------+
+| <!DOCTYPE html> | ![On p tags](pix/html-01.png) |
+| <h1>My website!</h1> | |
+| <p>This is my web | |
+| site. Thanks for stopping by!</p> | |
+| | |
+| <p>Now my website is live!</p> | |
+| Here is some more text. | |
+| There are | |
+| no paragraph tags on this stuff. | |
+| So it | |
+| will all appear as one paragraph. | |
+| | |
+| Despite being on multiple lines. | |
+| | |
+| | |
+| Even this! | |
++-----------------------------------+-----------------------------------+
+
+This will seem strange at first, but this is the use of HTML as a markup
+language: it allows you to style your document with tags and write it in
+whatever way is convenient.
+
+Let\'s learn more about what HTML can do.
+
+### Headings
+
+In addition to paragraphs (`<p>`), we can specify headings with inside
+`<h1></h1>` tags. Heading tags are for your page\'s title and section
+headings in the document:
+
+- `<h1></h1>` -- Main and largest headings
+- `<h2></h2>` -- Subheadings (smaller)
+- `<h3></h3>` -- Sub-subheadings (yet smaller)
+- `<h4></h4>` -- Etc., etc.
+
++-----------------------------------+-----------------------------------+
+| <h1> | ![On p and h# |
+| This is a top-level heading.</h1> | tags](pix/html-02.png) |
+| | |
+| <p | |
+| >Here is some paragraph text.</p> | |
+| | |
+| | |
+| <p>And here is some more...</p> | |
+| | |
+| < | |
+| h2>This is a subheading (h2)</h2> | |
+| | |
+| <p>And another paragraph.</p> | |
+| | |
+| <h2>And here is ano | |
+| ther subheading (Also an h2)</h2> | |
+| | |
+| <p>Etc. etc...</p> | |
++-----------------------------------+-----------------------------------+
+
+#### A preview to CSS
+
+It is very important to use headings like this for your pages. Notice
+that on this website, headings come in different colors, text-alignment
+and sizes for emphasis. If we use these heading tags, when we clear CSS,
+we can easily style all `<h2>`, for example, to be the size and color
+and alignment we want.
+
+## Text formatting
+
+HTML can also be used to do text formatting. We can make bold, italic,
+underlined or struck through text with more HTML tags:
+
++-----------------------------------+-----------------------------------+
+| | ![formatted |
+| <p>This is <b>bold text</b>.</p> | text](pix/html2-01.png) |
+| | |
+| < | |
+| p>This is <i>italic text</i>.</p> | |
+| | |
+| | |
+| <p>This is <u>underlined</u>.</p> | |
+| | |
+| <p>T | |
+| his is <s>struck through</s>.</p> | |
++-----------------------------------+-----------------------------------+
+
+## Semantic Tags
+
+While `<b></b>` and `<i></i>` do exist, it\'s actually better *not* to
+use them directly in text.
+
+Try using `<strong></strong>` instead of `<b></b>` and `<em></em>`
+instead of `<i></i>`. By default, they will look exactly the same. You
+complain that they require more key presses, but it\'s thought to be a
+very bad idea to modify lower-level tags with CSS directly.
+
+Note that some bold words on this site have **different color for
+emphasis**. This is a setting set via CSS for all `<strong>` tags. It
+would not be a good idea for us to use this for `<b>`, since there might
+be a non-colored situation we want to occasionally use it in.
diff --git a/content/html2.md b/content/html2.md
new file mode 100644
index 0000000..9865e88
--- /dev/null
+++ b/content/html2.md
@@ -0,0 +1,7 @@
+---
+title: "Images and Links in HTML"
+draft: true
+---
+## Links
+
+We need to create links
diff --git a/content/html4.md b/content/html4.md
new file mode 100644
index 0000000..adb8eb3
--- /dev/null
+++ b/content/html4.md
@@ -0,0 +1,32 @@
+---
+title: "Doing HTML Right"
+draft: true
+---
+We\'ve noted that HTML is very forgiving
+
+## A look at a decent template
+
+I have a template file that I use for this website that includes all the
+basics. When I make a new page, I just copy the template and add the
+content. Here is what the template looks like:
+
+``
+
+ <!DOCTYPE html>
+ <html lang=en>
+ <head>
+ <title>Your page title</title>
+ <meta charset="utf-8"/>
+ <link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
+ <link rel='stylesheet' type='text/css' href='style.css'>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <link rel='alternate' type='application/rss+xml' title='Site Title RSS' href='/rss.xml'>
+ </head>
+ <body>
+ <header><h1>Your page title</h1></header>
+
+ <nav></nav>
+
+ <main>
+
+ Put all your page content here in the <main> tag.
diff --git a/content/i2p.md b/content/i2p.md
new file mode 100644
index 0000000..fec9d8c
--- /dev/null
+++ b/content/i2p.md
@@ -0,0 +1,101 @@
+---
+title: "i2p"
+date: 2021-07-01
+img: 'i2p.svg'
+icon: 'itoopie.svg'
+tags: ['service']
+short_desc: "A private and uncensorable web-layer similar to Tor."
+---
+
+Now you have a website, why not offer it in a private alternative such
+as the Invisible Internet?
+
+## Setting up I2P
+
+There are 2 main I2P implementations, I2P and i2pd, we are using i2pd in
+this guide because it\'s easier to use in servers.
+
+### Installing I2P
+
+i2pd is in most repos, in debian/ubuntu you can install it simply with
+
+```sh
+apt install i2pd
+```
+
+### Enabling I2P
+
+We are going to create a user for i2pd, because i2pd finds the
+configuration files in its home directory. And it\'s easier (and more
+tidy) to have it in a separate user:
+
+```sh
+useradd -m i2p -s /bin/bash
+su -l i2p
+mkdir ~/.i2pd
+cd ~/.i2pd
+```
+
+Now that you\'re in \~/.i2pd, you have to create a file named
+\"tunnels.conf\". Which is the config file for every hidden service
+you\'re offering over I2P, the content should be like this:
+
+```systemd
+[example]
+type = http
+host = 127.0.0.1
+port = 8080
+keys = example.dat
+```
+
+### Getting your I2P Hostname
+
+Then, run `/usr/sbin/i2pd --daemon` to start i2pd and we can retreive
+our I2P hostname.
+
+This can be done in lynx or a command-line browser by going to
+`http://127.0.0.1:7070/?page=i2p_tunnels` to get your I2P hostname.
+
+You can also run these commands to find your hostname:
+
+```sh
+printf "%s.b32.i2p
+" $(head -c 391 /home/i2p/.i2pd/example.dat |sha256sum|xxd -r -p | base32 |sed s/=//g | tr A-Z a-z)
+```
+
+## Adding the Nginx Config
+
+From here, the steps are almost identical to setting up a normal website
+configuration file. Follow the steps as if you were making a new website
+on the webserver [tutorial](/basic/nginx) up until the server block of
+code. Instead, paste this:
+
+```nginx
+server {
+ listen 127.0.0.1:8080 ;
+ root /var/www/example ;
+ index index.html ;
+}
+```
+
+#### Clarifications
+
+####
+
+Nginx will listen in port 8080, but i2pd will forward your port 8080 to
+the i2p site port 80. This way you don\'t have to deal with server names
+or anything like that
+
+From here we are almost done, all we have to do is enable the site and
+reload nginx which is also covered in [the webserver
+tutorial](nginx.html#enable).
+
+### Update regularly!
+
+Make sure to update I2P on a regular basis by running:
+
+```sh
+apt update && apt install i2pd
+```
+
+**Contributor** - [qorg11](https://qorg11.net)
diff --git a/content/imgcompress.md b/content/imgcompress.md
new file mode 100644
index 0000000..49dab19
--- /dev/null
+++ b/content/imgcompress.md
@@ -0,0 +1,51 @@
+---
+title: "Image compression"
+date: 2021-07-17
+---
+Image files will usually have the most impact on the speed of your
+websites (aside from Ad/tracker scripts). Learn to slim down your images
+using the ubiquitous *ImageMagick* to make your websites faster on slow
+internet connections.
+
+{{< img alt="Image network speed" src="/pix/imgcompress-network.png" link="/pix/imgcompress-network.png" >}}
+
+For the examples, I decided to use
+[this](https://commons.wikimedia.org/wiki/File:Tabby_cat_with_blue_eyes-3336579.jpg)
+public domain image.
+
+{{< img alt="Compressed image of a cat" src="/pix/imgcompress-cat.png" link="/pix/imgcompress-cat.png" >}}
+
+There are many ways to decrease image size using ImageMagick, the
+simplest is to use the `-quality` option, which will compress the image
+without changing the resolution. This option takes the value you want to
+compress by (between 1 and 100, the lower the value, the lower the file
+size). For example:
+
+ convert in.jpg -quality 50 out.jpg
+
+Compressing the example image above results in the following file size
+changes:
+
+```
+ Quality Size
+ ---------- ------
+ Original 2.1M
+ 90 1.7M
+ 80 844K
+ 70 588K
+ 60 448K
+ 50 368K
+ 40 308K
+ 30 248K
+ 20 184K
+ 10 116K
+```
+
+Due to the images high resolution, it is usable in this website even
+when highly compressed (30% quality, still looks decent in my opinion).
+
+## Contribution
+
+- [Musse](https://na20a.neocities.org/)
+- Monero:
+ `83is3y69Xv4fkFsTpZhw5c3bfxtimupfgTdpERHM1WtMNAwSqFjTCJm3VabyBKXKnL873dWPmqj4bRcgkm9oCktgQrzmhHd`{.crypto}
diff --git a/content/irc.md b/content/irc.md
new file mode 100644
index 0000000..f61abca
--- /dev/null
+++ b/content/irc.md
@@ -0,0 +1,946 @@
+---
+title: "IRC"
+date: 2020-07-03
+icon: 'irc.svg'
+tags: ['service']
+short_desc: "Self-hosting the Internet's classic chat protocol."
+---
+
+Creating your own chat server for you and your friends is easy, and you
+don\'t have to rely on a complicated system to get started. IRC is an
+old but gold protocol, and has clients for basically every operating
+system made since the 80s, with many powerful modern ones on Linux, Mac,
+and Windows.
+
+Having a chat server for you and your friends makes it impossible for a
+group of arbitrarily appointed moderators to deplatform you for
+wrong-think, and gives you greater freedom of communication.
+
+## Installing an IRCd {#installing}
+
+An IRCd is short for \"IRC daemon\", which just means an IRC server. The
+most easy IRCd to set up is [Ergo](https://ergo.chat/).
+
+The first thing you need to do is create a new user for the server to be
+run by. This is good practice for installing software/servers manually,
+as it give you more fine-grained control over which permissions the
+application has.
+
+```sh
+useradd -m ergo -s /bin/bash
+```
+
+Next, we want to switch to our newly created `ergo` user and create the
+server directory.
+
+```sh
+sudo -i -u ergo
+mkdir server
+```
+
+You can find the latest release of Ergo on its GitHub [latest
+release](https://github.com/ergochat/ergo/releases/latest) page.\
+There are several platforms available, but you want to choose Linux,
+most likely `linux-x86_64`.\
+Once you have selected the correct package, copy its URL and replace the
+release url with the package URL (still as the `ergo` user):
+
+```sh
+wget "https://github.com/ergochat/ergo/releases/download/v2.7.0/ergo-2.7.0-linux-x86_64.tar.gz"
+tar -xf ergo-2.7.0-linux-x86_64.tar.gz
+mv ergo-2.7.0-linux-x86_64/*
+rm -r ergo-2.7.0-linux-x86_64*
+```
+
+Executing `ls -l` should now yield something like this:
+
+```sh
+-rw-r--r-- 1 ergo ergo 118825 Jun 8 00:51 CHANGELOG.md
+-rw-r--r-- 1 ergo ergo 1983 May 31 01:48 README
+-rw-r--r-- 1 ergo ergo 41440 Jun 8 00:42 default.yaml
+drwxr-xr-x 2 ergo ergo 4096 Jul 1 09:01 docs
+-rwxr-xr-x 1 ergo ergo 9654272 Jun 8 00:53 ergo
+-rw-r--r-- 1 ergo ergo 1753 May 31 01:48 ergo.motd
+drwxr-xr-x 2 ergo ergo 12288 Jul 1 09:01 languages
+-rw-r--r-- 1 ergo ergo 39722 Jun 8 00:42 traditional.yaml
+```
+
+If you see something similar to the above, that means Ergo is installed,
+although not quite ready to run yet.
+
+## Configuring Ergo {#configuring}
+
+Now that Ergo is installed, you want to configure it to fit the needs of
+your group.\
+The configuration in this section is tailored towards a small group of
+people, and less for a possibly large network, but it should work for
+any size of group.
+
+First thing, make sure you\'re still using the `ergo` user, and are in
+the `~/server` directory.\
+If you aren\'t, you can run the following to get back there:
+
+```sh
+sudo -i -u ergo
+cd ~/server
+```
+
+To start configuring, we need to copy some files:
+
+```sh
+cp default.yaml ircd.yaml
+cp ergo.motd ircd.motd
+```
+
+Next, generate certificate files for TLS:
+
+```sh
+./ergo mkcerts
+```
+
+Ergo comes with a default configuration file with detailed documentation
+that can be used to guide you through the configuration process. This
+guide will help you setup the server for a typical use-case, but if you
+see any settings that you would like to change along the way, go ahead
+and change them, as long as you know what you\'re doing.
+
+The next steps involve editing the newly copied `ircd.yaml` file. If you
+do not know how to edit text files from the command line, you can use
+`nano`, which is very simple, using arrow keys to navigate, `CTRL+O` to
+save, and `CTRL+X` to exit.\
+Another option is `vim`, which is a much more powerful text editor, but
+has a learning curve. It is only recommended for this guide if you
+already know how to use it.\
+Lastly, you can copy the `ircd.yaml` file to a text editor on your
+computer and edit it with a GUI text editor of your choice. If that is
+what you choose to do, you may want to just download the file from
+[Ergo\'s
+GitHub](https://raw.githubusercontent.com/ergochat/ergo/master/default.yaml),
+edit it on your computer, clear the `ircd.yaml` file on the server, and
+then paste the contents from your computer into the blank file.\
+No matter how you do it, the next steps assume you can edit the
+configuration file.
+
+**Note**:\
+The options highlighted in this section are not a complete overview of
+all options. Instead, the options shown are the ones which are most
+relevant to a small network.\
+You should read over the configuration file yourself if you are curious
+about everything you can change.
+
+### Network and server names {#configuring-names}
+
+One of the first properties in the config file is network name. You can
+change this to whatever you like, as it will show up as the name when
+you connect to the server.
+
+```yaml
+# network configuration
+network:
+ # name of the network
+ name: "Land-Chat"
+```
+
+Change the server name to your server\'s domain name.
+
+```yaml
+# server configuration
+server:
+ # server name
+ name: "example.org"
+```
+
+### Network password {#configuring-password}
+
+The next step is optional, depending on if you want your network
+password protected or not. The benefit of password protection is fairly
+obvious; nobody can connect to your network unless you gave them the
+password. If you\'re wanting to run a public network which anyone can
+join and create a channel, you want to skip this, but for personal
+setups, it is highly recommended.
+
+Generate a password to use by executing the following:
+
+```sh
+./ergo genpasswd
+```
+
+It will ask you to enter a password and confirm it, then you will be
+given a hashed password.\
+Copy this password, and paste it into the following field (also removing
+the `#` before the `password:` line):
+
+```yaml
+# password to login to the server, generated using `ergo genpasswd`:
+password: "<your hashed password>"
+```
+
+### Message of the day (MotD) {#configuring-motd}
+
+Change the MotD (**M**essage **o**f **t**he **D**ay) file to the one you
+copied earlier:
+
+```yaml
+# motd filename
+# if you change the motd, you should move it to ircd.motd
+motd: ircd.motd
+```
+
+Feel free to edit `ircd.motd` to your heart\'s content. Its contents
+will be sent to clients when they connect to the network.
+
+### IP limits {#configuring-ip-limits}
+
+For security purposes, you might want to limit the amount of client
+connections per IP. For a private network, 4 is likely the maximum
+amount of connections you will have per IP, so that is a safe value.\
+If your network is password protected, this is less of an issue, since
+the only people connecting will be people who have the password. The
+following is the default, but you can change it to be whichever value
+you like:
+
+```yaml
+# IP-based DoS protection
+ip-limits:
+ # whether to limit the total number of concurrent connections per IP/CIDR
+ count: true
+ # maximum concurrent connections per IP/CIDR
+ max-concurrent-connections: 16
+```
+
+### IP cloaking {#configuring-ip-cloaking}
+
+Traditionally, IRC networks expose users\' IP addresses to everyone.
+This is not a good practice for privacy, however. With Ergo, IP cloaking
+is enable by default. You can enable or disable it if you like, and
+change how it looks to users.\
+In this case, `netname` was changed to `"chad"`.
+
+```yaml
+# IP cloaking hides users' IP addresses from other users and from channel admins
+# (but not from server admins), while still allowing channel admins to ban
+# offending IP addresses or networks. In place of hostnames derived from reverse
+# DNS, users see fake domain names like pwbs2ui4377257x8.irc. These names are
+# generated deterministically from the underlying IP address, but if the underlying
+# IP is not already known, it is infeasible to recover it from the cloaked name.
+# If you disable this, you should probably enable lookup-hostnames in its place.
+ip-cloaking:
+ # whether to enable IP cloaking
+ enabled: true
+
+ # whether to use these cloak settings (specifically, `netname` and `num-bits`)
+ # to produce unique hostnames for always-on clients. you can enable this even if
+ # you disabled IP cloaking for normal clients above. if this is disabled,
+ # always-on clients will all have an identical hostname (the server name).
+ enabled-for-always-on: true
+
+ # fake TLD at the end of the hostname, e.g., pwbs2ui4377257x8.irc
+ # you may want to use your network name here
+ netname: "chad"
+```
+
+### Password enforcement adjustments for HexChat (and possibly other clients) {#configuring-hexchat-password}
+
+Ergo offers account registration to allow users to do things like use
+history and bouncer features, register channels, etc.\
+In clients such as HexChat, server passwords may conflict with account
+passwords, so the following setting should be enabled if you wish to use
+accounts with clients such as HexChat.\
+Note that this could under some circumstances be considered a security
+hazard, as a user with an account does not need to know the server
+password to connect, although that user would have needed to register an
+account before the server had a password, and then a password would need
+to have been set after the fact, so this can be considered a very small
+concern if your setup has always had a password.\
+Also keep in mind that this setting has no effect if your network does
+not even have a password at all.
+
+```yaml
+# some clients (notably Pidgin and Hexchat) offer only a single password field,
+# which makes it impossible to specify a separate server password (for the PASS
+# command) and SASL password. if this option is set to true, a client that
+# successfully authenticates with SASL will not be required to send
+# PASS as well, so it can be configured to authenticate with SASL only.
+skip-server-password: true
+```
+
+### Multiclient, always-on clients, history, etc {#configuring-multiclient}
+
+Traditionally, IRC servers have no message history, and once you close
+your client, you cannot receive messages, and are not shown to be online
+at all. Ergo includes functionality to allow users to both receive
+history, and keep their clients \"online\" even after they have left. It
+also allows multiple clients to connect to the same account.\
+If you are running a private network for friends, you should set
+`always-on` and `auto-away` to `opt-out`, to have all users with
+accounts to appear as if they are online at all times, and be able to
+receive messages when they are offline.\
+For a public network, keep everything as their default values, since you
+probably do not want randoms having this by default.\
+If for some reason you do not want any of these features at all, you can
+set `enabled` to `false`, but this is not recommended. Below are the
+recommended values for a private network (e.g. for friends) where users
+with accounts will be able to receive messages and history while they
+are offline.
+
+```yaml
+# multiclient controls whether Ergo allows multiple connections to
+# attach to the same client/nickname identity; this is part of the
+# functionality traditionally provided by a bouncer like ZNC
+multiclient:
+ # when disabled, each connection must use a separate nickname (as is the
+ # typical behavior of IRC servers). when enabled, a new connection that
+ # has authenticated with SASL can associate itself with an existing
+ # client
+ enabled: true
+
+ # if this is disabled, clients have to opt in to bouncer functionality
+ # using nickserv or the cap system. if it's enabled, they can opt out
+ # via nickserv
+ allowed-by-default: true
+
+ # whether to allow clients that remain on the server even
+ # when they have no active connections. The possible values are:
+ # "disabled", "opt-in", "opt-out", or "mandatory".
+ always-on: "opt-out"
+
+ # whether to mark always-on clients away when they have no active connections:
+ auto-away: "opt-out"
+
+ # QUIT always-on clients from the server if they go this long without connecting
+ # (use 0 or omit for no expiration):
+ #always-on-expiration: 90d
+```
+
+### VHosts {#configuring-vhosts}
+
+IP cloaking was mentioned previously, and somewhat related to that, Ergo
+includes \"vhost\" functionality, which allows users to set a custom
+IP/host string. This is mostly for cosmetic value, and does not
+interfere with operators being able to see actual IP addresses for
+banning, but if you do not want it enable for some reason, you can
+disable it.
+
+```yaml
+# vhosts controls the assignment of vhosts (strings displayed in place of the user's
+# hostname/IP) by the HostServ service
+vhosts:
+ # are vhosts enabled at all?
+ enabled: true
+```
+
+### Channels {#configuring-channels}
+
+Channels are where everyone on an IRC network talk. By default, anyone
+can create a channel, and anyone with an account can register one. The
+difference between a normal channel and a registered one is that the
+registered one will preserve the operator status of the person who
+created, whereas a normal channel\'s owner will lose operator status if
+they leave the channel or disconnect from the network.\
+There are various settings for channels available, but the defaults are
+suitable for a private network with trust among users, or where you just
+want anyone to have the ability to create a channel. Below are the
+default values:
+
+```yaml
+# channel options
+channels:
+ # modes that are set when new channels are created
+ # +n is no-external-messages and +t is op-only-topic
+ # see /QUOTE HELP cmodes for more channel modes
+ default-modes: +nt
+
+ # how many channels can a client be in at once?
+ max-channels-per-client: 100
+
+ # if this is true, new channels can only be created by operators with the
+ # `chanreg` operator capability
+ operator-only-creation: false
+
+ # channel registration - requires an account
+ registration:
+ # can users register new channels?
+ enabled: true
+
+ # restrict new channel registrations to operators only?
+ # (operators can then transfer channels to regular users using /CS TRANSFER)
+ operator-only: false
+
+ # how many channels can each account register?
+ max-channels-per-account: 15
+```
+
+### Operators (administrators, etc) {#configuring-operators}
+
+The IRC term for an administrator or another privileged user is
+\"operator\", or \"oper\" for short.\
+Ergo\'s opers have different permissions that can be granted to them,
+and are defined in \"classes\", basically groups of permissions under a
+name. For example, \"chat-moderator\" and \"server-admin\" are defined
+in the default configuration:
+
+```yaml
+# operator classes
+oper-classes:
+ # chat moderator: can ban/unban users from the server, join channels,
+ # fix mode issues and sort out vhosts.
+ "chat-moderator":
+ # title shown in WHOIS
+ title: Chat Moderator
+
+ # capability names
+ capabilities:
+ - "kill"
+ - "ban"
+ - "nofakelag"
+ - "roleplay"
+ - "relaymsg"
+ - "vhosts"
+ - "sajoin"
+ - "samode"
+ - "snomasks"
+
+ # server admin: has full control of the ircd, including nickname and
+ # channel registrations
+ "server-admin":
+ # title shown in WHOIS
+ title: Server Admin
+
+ # oper class this extends from
+ extends: "chat-moderator"
+
+ # capability names
+ capabilities:
+ - "rehash"
+ - "accreg"
+ - "chanreg"
+ - "history"
+ - "defcon"
+ - "massmessage"
+```
+
+The above can be kept with their default values, but you are free to
+modify them or create any new classes that are appropriate for your
+setup.\
+Next, let\'s actually create an operator account:
+
+```yaml
+# ircd operators
+opers:
+ # default operator named 'gigachad'; log in with /OPER gigachad <password>
+ "gigachad":
+ # which capabilities this oper has access to
+ class: "server-admin"
+
+ # custom whois line
+ whois-line: is the server administrator
+
+ # custom hostname
+ vhost: "gigachad"
+
+ # normally, operator status is visible to unprivileged users in WHO and WHOIS
+ # responses. this can be disabled with 'hidden'. ('hidden' also causes the
+ # 'vhost' line above to be ignored.)
+ hidden: false
+
+ # modes are modes to auto-set upon opering-up. uncomment this to automatically
+ # enable snomasks ("server notification masks" that alert you to server events;
+ # see `/quote help snomasks` while opered-up for more information):
+ #modes: +is acjknoqtuxv
+
+ # operators can be authenticated either by password (with the /OPER command),
+ # or by certificate fingerprint, or both. if a password hash is set, then a
+ # password is required to oper up (e.g., /OPER dan mypassword). to generate
+ # the hash, use `ergo genpasswd`.
+ password: "<your oper password>"
+```
+
+This is a modified version of the default oper entry. The account name
+is \"gigachad\", but you can change it to anything.\
+Replace `<your oper password>` with a password generated by
+`./ergo genpasswd`, and you will have a new oper account to use.\
+Note that to log into an oper account, clients have to enter
+`/OPER <oper name> <oper password>` each time they log in. This can be
+automated by most clients by setting the command to be executed when the
+client logs in. In the case of HexChat, you can edit your network and
+add the command to the `Connect commands` tab of the menu.\
+You can copy everything from `"gigachad"` to the end of the line, paste
+it again, and change the name to create another oper account. Another,
+less privileged example of an oper is shown as a comment below the above
+configuration snippet.
+
+### Chat history {#configuring-history}
+
+Traditionally, IRC networks do not store, relay, or handle chat history
+in any way.\
+On a privacy standpoint, this is a good thing, since chats are entirely
+ephemeral and handled by clients.\
+On a practicality standpoint, this is a bad thing, since people have to
+keep a client connected 24/7 to see message history.\
+For normalfriends, this can be a big problem, not only because having to
+stay online 24/7 is just annoying or infeasible, but also because they
+are likely used to chat platforms that handle history for them.\
+With this in mind, enabling history is a good idea if you want to move
+friends over to IRC, and will make things a lot more pleasant for
+private networks.
+
+Ergo\'s `history` configuration group is very long, so it is encouraged
+to read over it yourself. This section will go over the most important
+pieces of that configuration group.
+
+History is not endless (unless you want it to be), and the amount that
+can be stored for channels is configurable:
+
+```yaml
+# how many channel-specific events (messages, joins, parts) should be tracked per channel?
+channel-length: 2048
+```
+
+History is already enabled by default, but that just means it is being
+collected, not relayed by default. To relay history to clients when they
+connect, change the following to the amount of messages that you think
+is appropriate:
+
+```yaml
+# number of messages to automatically play back on channel join (0 to disable):
+autoreplay-on-join: 250
+```
+
+History older than a certain time can be configured to be deleted or be
+inaccessible. The default cutoff time is 1 week, but this is
+configurable as well.
+
+```yaml
+# options to delete old messages, or prevent them from being retrieved
+restrictions:
+ # if this is set, messages older than this cannot be retrieved by anyone
+ # (and will eventually be deleted from persistent storage, if that's enabled)
+ expire-time: 1w
+```
+
+By default, Ergo only stores chat history in memory, so when the server
+restarts, all history is lost. If you wish to have chat history persist
+beyond restarts, you must store it in a MySQL database:
+
+```yaml
+# options to store history messages in a persistent database (currently only MySQL).
+# in order to enable any of this functionality, you must configure a MySQL server
+# in the `datastore.mysql` section.
+persistent:
+ enabled: true
+
+ # store unregistered channel messages in the persistent database?
+ unregistered-channels: true
+
+# connection information for MySQL (currently only used for persistent history):
+mysql:
+ enabled: false
+ host: "localhost"
+ port: 3306
+ # if socket-path is set, it will be used instead of host:port
+ #socket-path: "/var/run/mysqld/mysqld.sock"
+ user: "ergo"
+ password: "hunter2"
+ history-database: "ergo_history"
+ timeout: 3s
+ max-conns: 4
+ # this may be necessary to prevent middleware from closing your connections:
+ #conn-max-lifetime: 180s
+```
+
+For privacy reasons, you may want to allow users to delete their own
+messages in history, or export their messages to JSON:
+
+```yaml
+# options to control how messages are stored and deleted:
+retention:
+ # allow users to delete their own messages from history?
+ allow-individual-delete: true
+
+ # if persistent history is enabled, create additional index tables,
+ # allowing deletion of JSON export of an account's messages. this
+ # may be needed for compliance with data privacy regulations.
+ enable-account-indexing: true
+```
+
+### Spam reduction {#configuring-spam}
+
+Most IRC networks have measures in place to reduce chat spam. By
+default, \"fakelag\" is enabled in Ergo, and that can deal with most
+aggregious chat spam.\
+If you are running a private network where user trust is high, you can
+disable it so that there are no limits on the speed that messages can be
+sent.
+
+```yaml
+# fakelag: prevents clients from spamming commands too rapidly
+fakelag:
+ # whether to enforce fakelag
+ enabled: true
+
+ # time unit for counting command rates
+ window: 1s
+
+ # clients can send this many commands without fakelag being imposed
+ burst-limit: 5
+
+ # once clients have exceeded their burst allowance, they can send only
+ # this many commands per `window`:
+ messages-per-window: 2
+
+ # client status resets to the default state if they go this long without
+ # sending any commands:
+ cooldown: 2s
+```
+
+## Starting and using your server
+
+Now that Ergo is both installed and configured, you can actually start
+using it!
+
+### Starting the server {#using-starting}
+
+First thing, make sure you\'re still using the `ergo` user, and are in
+the `~/server` directory.\
+If you aren\'t, you can run the following to get back there:
+
+```sh
+sudo -i -u ergo
+cd server
+```
+
+Starting the server is done in one command:
+
+```sh
+./ergo run
+```
+
+It will stay online until you close the terminal, or press CTRL+C.
+Don\'t worry, the next section goes over how to make it run like a
+normal server with a SystemD service.\
+If you have not already, make sure the port `6697` is not blocked on
+your server. If you are using UFW as your firewall, you need to run
+`ufw enable 6697` (not as the `ergo` user, of course).\
+If you make and configuration changes while the server is running, you
+can apply them without restarting by typing `/rehash` as an operator.
+
+### Connecting to the server {#using-connecting}
+
+To use IRC, you of course need an IRC client. There are many choices
+available, but the most widely used for Windows and Linux is
+[HexChat](https://hexchat.github.io/). On Mac, you have a slightly nicer
+option with [Textual](https://www.codeux.com/textual/), although you
+have to [compile it from
+source](https://github.com/Codeux-Software/Textual/#building-textual) if
+you want to use it for free.\
+A more user-friendly and modern client choice is TheLounge, which is
+explained in the last section of this guide, if you want to look into
+it.
+
+Connecting with HexChat is very easy. When you start it, you will see
+something like this:
+
+{{< img alt="HexChat network select" src="/pix/irc/hexchat-network-select.png" link="/pix/irc/hexchat-network-select.png" >}}
+
+From there, you should click `+ Add` and name the server whatever you
+like (so you can find it on the server list).\
+Once you have created a new server and named it, select it and click
+`Edit...`. A menu will show up like the one below. Change the domain to
+whatever domain your server is running on, and make sure to put in your
+server password if you set one.
+
+{{< img alt="HexChat network edit menu" src="/pix/irc/hexchat-network-edit.png" link="/pix/irc/hexchat-network-edit.png" >}}
+
+Once you\'re done editing the network, click `(X) Close`, select your
+network from the network list, and click `Connect`.\
+If all is well, you should be connected!
+
+{{< img alt="HexChat connection complete" src="/pix/irc/hexchat-connection-complete.png" link="/pix/irc/hexchat-connection-complete.png" >}}
+
+The process is very similar on Textual.\
+Create a new network and connect to it. Note that it will ask if you
+want to connect even though the certificate is unsigned. This is due to
+the self-signed certificates generated for the server, and is not a
+problem or security vulnerability, it is just a little annoying.
+
+{{< img alt="Textual network edit menu" src="/pix/irc/textual-network-edit.png" link="/pix/irc/textual-network-edit.png" >}}
+
+Surviving restarts with a SystemD service
+
+In the beginning of the last section, Ergo was started by simply running
+`./ergo run`, but this is only suitable for testing. To have a proper
+server setup, you need to run it as a service. This can be achieved via
+a SystemD service.
+
+Before creating your service file, make sure you are in `~/server` as
+the `ergo` user.\
+Once you have done that, create a file called `start.sh` with the
+following content:
+
+```sh
+#!/bin/bash
+./ergo run
+```
+
+Save the file, then mark it as executable:
+
+```sh
+chmod +x start.sh
+```
+
+Now, create a file called `ergo.service` with the following content:
+
+```systemd
+[Unit]
+Description=Ergo IRC server
+After=network.target
+# If you are using MySQL for history storage, comment out the above line
+# and uncomment these two instead (you must independently install and configure
+# MySQL for your system):
+# Wants=mysql.service
+# After=network.target mysql.service
+
+[Service]
+Type=simple
+User=ergo
+WorkingDirectory=/home/ergo/server
+ExecStart=/home/ergo/server/start.sh
+ExecReload=/bin/kill -HUP $MAINPID
+Restart=on-failure
+LimitNOFILE=1048576
+# Uncomment this for a hidden service:
+# PrivateNetwork=true
+
+[Install]
+WantedBy=multi-user.target
+```
+
+You now have your service file, but it is not installed yet. To install
+it, switch to your normal user, and execute the following lines to
+install, enable, and start the SystemD service:
+
+```sh
+ln -s /home/ergo/server/ergo.service /etc/systemd/system/ergo.service
+systemctl enable ergo
+systemctl start ergo
+```
+
+Ergo is now installed and running as a service, and will automatically
+start when the system boots.
+
+## Registering accounts and channels {#registering}
+
+Account and channel registration were mentioned multiple times in this
+guide, and are indeed very important parts of the modern IRC ecosystem.
+You can connect to most IRC networks and talk without creating an
+account, but you will not be able to reserve your nickname or register
+channels, so it is important to register an account.
+
+### Registering an account with NickServ {#registering-accounts}
+
+First, make sure you are connected to your IRC network. Once you are,
+type `/nickserv help` to make sure NickServ (the registration system) is
+working propertly.\
+If all is well, type the following, replacing `<your password>` with the
+password you want to use:
+
+```txt
+/nickserv register <your password>
+```
+
+At this point, you are now registered!\
+The final step is to configure authentication with your client.
+
+In HexChat, all that needs to be done is changing `Login method` to
+`SASL (username + password)`, and entering your NickServ password that
+you used earlier into the password field:
+
+{{< img alt="HexChat SASL in network edit menu" src="/pix/irc/hexchat-sasl.png" link="/pix/irc/hexchat-sasl.png" >}}
+
+In Textual, open up your network in the menu, and click `Identity` under
+`Server Properties`. Enter your password in `Personal Password`, and
+check `Wait for identification before joining channels`.
+
+{{< img alt="Textual identity menu" src="/pix/irc/textual-identity.png" link="/pix/irc/textual-identity.png" >}}
+
+You will now be logged into your account when you connect to your
+network.
+
+### Registering channels with ChanServ {#registering-channels}
+
+Once you have an account registered, you can register channels with
+ChanServ.\
+To do so, join the channel you want to register, then type the
+following, replacing `<your channel>` with the name of the channel you
+want to register:
+
+```txt
+/chanserv register #<your channel>
+```
+
+You are now the channel owner, and are free to appoint operators,
+administrators, etc for it. When you go offline, you won\'t lose
+ownership, and you cannot be removed as the owner unless you unregister
+the channel later.
+
+## Moderation
+
+Like any chat, there will come a point where you need to use moderation
+tools to keep things under control. Many IRC setup guides do not go over
+moderation, so it can be stressful when operators need to actually use
+moderation tools.\
+The main difference between IRC and other chat systems in terms of
+moderation is the difference between channel bans and network bans.
+Channel ban keeps a person out of channel a channel, whereas a network
+ban keeps a person out of the entire network.
+
+### Understanding masks {#moderation-masks}
+
+Bans are applied \"masks\", which are formatted pieces of text that
+contain a user\'s nick (username), their realname value, and their IP
+address or host.\
+This is what a mask looks like: `nick!~nick-dude@127.0.0.1`.\
+In bans, asterisks can be used as wildcards, which is useful for banning
+IP address ranges, patterns of nicknames, or whatever else you can think
+of.\
+A ban on the nick `person`, for example, would look like this:
+`person!*@*`.\
+A ban on anyone with the IP address `127.0.0.1` would look like this:
+`*!*@127.0.0.1`
+
+### Discovering real IPs {#moderation-real-ips}
+
+Even if IP cloaking is enabled on your network, you can still obtain
+real IP addresses/hosts if you are an operator. See the **Operators**
+part of the configuration section of this guide on how to become an
+operator.\
+To find out a user\'s real IP, simply type `/whois` along with the
+user\'s nick, and you will see information about the user, along with
+their real IP address/host.\
+`/whois` is not a command that is exclusive to operators, but it does
+not reveal as much information to non-operators.
+
+### Banning someone from the network {#moderation-network-ban}
+
+Any netword-wide moderation action requires being an operator. See the
+**Operators** part of the configuration section of this guide on how to
+become an operator.\
+Banning someone from the network is achieved with the `/kline` command.
+To see more info on the command, type `/helpop kline`.\
+
+To ban a nick from the network:
+
+```txt
+/kline andkill <nick>!*@*
+```
+
+To ban an IP address or host from the network:
+
+```txt
+/kline andkill *!*@<IP or mask>
+```
+
+To unban a mask, you can use the `/unkline` command with the mask you
+want to unban.
+
+### Banning someone from a channel {#moderation-channel-ban}
+
+Channel owners, administrators, and operators can ban people from
+channels. This is not the same as banning someone from the network,
+since it only has an effect on one channel. Additionally, a channel
+operator is not the same as a network operator.
+
+To ban someone in a channel, type the following in that channel,
+replacing `<mask>` with the user\'s mask:
+
+```txt
+/mode +b <mask>
+```
+
+Note that this will only ban the user, not kick them immediately. You
+will want to run `/kick` along with the user\'s nick to also kick them.\
+To unban a user, run the command above, but replace the `+` with a `-`.\
+You can see who is banned in a channel by typing `/banlist`.
+
+### Muting people in a channel {#moderation-muting}
+
+By default, anyone can speak in an IRC channel. To change this, you must
+be a channel owner, administrator, or operator.\
+Channels, along with users, have modes, which modify their behavior.
+There is a special mode for channels called `m` (moderated) which
+requires users to be privileged in some way to talk.\
+To set a channel as moderated, type the following in the channel:
+
+```txt
+/mode +m
+```
+
+Now, users must be an owner, administrator, operator, or be voiced to
+talk in the channel This be reversed by typing the command above, but
+changing the `+` to a `-`.\
+To voice a user, run the following, replacing *\<nick\>* with the
+user\'s nick:
+
+```txt
+/mode +v <nick>
+```
+
+Unvoice the user by typing the above command, but replacing the `+` with
+a `-`.
+
+### Appointing channel administrators and operators {#moderation-appointing}
+
+Assuming you a channel owner, you can appoint both administrators and
+operators. If you are only an operator, you may only appoint operators.\
+The difference between administrator and operator is mainly that
+administrators cannot have their privileges taken away by operators,
+only owners. To appoint an administrator, type the following, replacing
+*\<nick\>* with the user\'s nick:
+
+```txt
+/mode +a <nick>
+```
+
+To appoint an operator, type the following, replacing *\<nick\>* with
+the user\'s nick:
+
+```txt
+/mode +o <nick>
+```
+
+You can also use `/op` and `/deop` on most clients to appoint and remove
+an operator.\
+To remove administrator or operator status, run either of the above
+commands, but replace the `+` with a `-`.
+
+Bringing modern-day features to IRC with TheLounge
+
+A large downside to IRC as a protocol is just how old it is, and the
+limitations that exist because of it. Other old protocols such as HTTP
+were built to be content-agnostic and versitile, but IRC was built with
+a very specific set of features, so it has not held up so well to
+contemporary chat systems.\
+A notable thing that IRC as a protocol is missing is file uploads, and
+other fancy features that many other chats have.\
+With that said, these problems can be fixed by clients, although many
+clients are still very primitive.
+
+[TheLounge](https://thelounge.chat/) is a modern self-hosted IRC web
+client that tries to make IRC as user-friendly as possible. It can be
+the answer to many of the complaints that normalfriends may have about
+IRC. It runs on anything with a web browser, can be \"installed\" since
+it is a PWA (Progressive Web App), and is optimized for both desktops
+and mobile devices. It keeps you logged in even when you are gone, and
+even supports file uploads and embeds.\
+Effectively, it brings IRC up to the standard of most other chat
+systems.
+
+If you would like to setup an instance of TheLounge for you and your
+friends, you can take a look at their [installation
+guide](https://thelounge.chat/docs/install-and-upgrade).\
+It is a self-hosted web app, so you can run it for multiple people, not
+just yourself.
+
+------------------------------------------------------------------------
+
+*Written by [Termer](https://termer.net/)*
diff --git a/content/jitsi.md b/content/jitsi.md
new file mode 100644
index 0000000..aa6bab4
--- /dev/null
+++ b/content/jitsi.md
@@ -0,0 +1,199 @@
+---
+title: "Jitsi"
+date: 2021-07-31
+icon: "jitsi.svg"
+tags: ['service']
+short_desc: "Video-chat software."
+---
+
+<dfn>Jitsi</dfn> is a set of open-source projects that allows you to easily
+build and deploy secure video conferencing solutions.
+
+Is really easy to install, and also a really good private, federated and
+libre alternative to Zoom or other video conferencing software. You can
+create calls just by typing the URL, and loging-in is not necessary.
+
+## Dependencies and Installation
+
+First, install some dependencies:
+
+```sh
+apt install gpg apt-transport-https nginx python3-certbot-nginx
+```
+
+Jitsi has its own package repository, so let\'s add it.
+
+```bash
+curl https://download.jitsi.org/jitsi-key.gpg.key | gpg --dearmor > /usr/share/keyrings/jitsi-keyring.gpg
+echo 'deb [signed-by=/usr/share/keyrings/jitsi-keyring.gpg] https://download.jitsi.org stable/' > /etc/apt/sources.list.d/jitsi-stable.list
+apt update -y
+```
+
+Ok. So now we can install Jitsi, but before we do that, let\'s setup the
+firewall `ufw`, in case you have it enabled, and the SSL certificate.
+
+## Enable Required Ports
+
+If you are using [ufw](/ufw) or another firewall, there are several
+ports we need to ensure are open:
+
+```sh
+ufw allow 80/tcp
+ufw allow 443/tcp
+ufw allow 10000/udp
+ufw allow 3478/udp
+ufw allow 5349/tcp
+ufw enable
+```
+
+For your information, these allow the following:
+
+- 80 TCP -- Certbot.
+- 443 TCP -- General access to Jitsi Meet.
+- 10000 UDP -- General network video/audio communications.
+- 3478 UDP -- Quering the stun server ([Coturn](/coturn), optional, needs config.js change to enable it).
+- 5349 TCP -- Fallback network video/audio communications over TCP (when UDP is blocked for example), served by [Coturn](/coturn).
+
+## SSL certificate
+
+I\'ll be using [certbot](/basic/certbot) and
+[Nginx](/basic/nginx) to generate a certificate for the
+Jitsi subdomain to allow encrypted connections.
+
+```sh
+certbot --nginx certonly -d meet.example.org
+```
+
+We will not create an Nginx config file for Jitsi because the Jitsi
+package we will be installing will do that automatically.
+
+## Installation
+
+To begin the installation process, just run:
+
+```sh
+apt install jitsi-meet
+```
+
+It will ask you for your `hostname`; there you\'ll need to input the
+subdomain you have just added to Nginx, like `meet.example.org`.
+
+For the SSL certificate, choose `I want to use my own certificate`.
+
+When it ask you for the certification key and cert files, input
+`/etc/letsencrypt/live/meet.example.org/privkey.pem` and
+`/etc/letsencrypt/live/meet.example.org/fullchain.pem` respectively.
+
+## Using Jitsi
+
+{{< img alt="Jitsi once installed" src="/pix/jitsi-01.webp" >}}
+
+Jitsi can be used in a browser by then just going to `meet.example.org`.
+
+Note that there are also Jitsi clients for all major platforms:
+
+- [Desktop](https://desktop.jitsi.org/Main/Download.html) (Windows,
+ MacOS, GNU/Linux)
+- Android ([F-Droid](https://f-droid.org/en/packages/org.jitsi.meet/)
+ and [Google
+ Play](https://play.google.com/store/apps/details?id=org.jitsi.meet))
+- [iPhone/iOS](https://apps.apple.com/us/app/jitsi-meet/id1165103905)
+
+**When using a Jitsi app for the first time, remember to go to the
+\"Settings\" menu and change your server name to the Jitsi site you just
+created.**
+
+When you create a video chatroom, its address will appear as
+`meet.example.org/yourvideochatname` and can be shared as such.
+
+## Security
+
+By default, anyone who has access to **meet.example.org** will be able
+to create a chatroom. You probably don\'t want that, so you\'ll need to
+set up some authentication. The simplest option is to handle
+authentication through the local [Prosody](/prosody) user
+database.
+
+### Prosody configuration
+
+First, we need to enable password authentication in
+[Prosody](/prosody). Edit
+`/etc/prosody/conf.avail/meet.example.org.cfg.lua`, and locate this
+block:
+
+```lua
+VirtualHost "meet.example.org"
+ authentication = "anonymous"
+```
+
+And change the authentication mode from `"anonymous"` to
+`"internal_hashed"`.
+
+Then, to enable guests to login and join your chatrooms, add the
+following block **after** the one you just edited:
+
+```lua
+VirtualHost "guest.meet.example.org"
+ authentication = "anonymous"
+ c2s_require_encryption = false
+```
+
+### Jitsi Meet configuration
+
+Next, in `/etc/jitsi/meet/meet.example.org-config.js`, uncomment the
+following line:
+
+```js
+var config = {
+ hosts: {
+ // anonymousdomain: 'guest.jitsi-meet.example.com',
+ },
+}
+```
+
+And change `'guest.jitsi-meet.example.com'` to
+`'guest.meet.example.org'`.
+
+### Jicofo configuration
+
+Finally, we configure Jicofo to only allow the creation of conferences
+when the request is coming from an authenticated user. To do so, add the
+following `authentication` section to `/etc/jitsi/jicofo/jicofo.conf`:
+
+```yaml
+jicofo {
+ authentication: {
+ enabled: true
+ type: XMPP
+ login-url: meet.example.org
+ }
+```
+
+### Create users in Prosody and restart the services
+
+You now need to register some users in [Prosody](/prosody), you
+can do so manually using `prosodyctl`:
+
+```sh
+prosodyctl register &ltusername> meet.example.org &ltpassword>
+```
+
+Finally, restart `prosody`, `jicofo`, and `jitsi-videobridge2`:
+
+```sh
+systemctl restart prosody
+systemctl restart jicofo
+systemctl restart jitsi-videobridge2
+```
+
+## More info
+
+This article is based on [the original
+documentation](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-quickstart).
+There you can find more details and configurations.
+
+- Written by [Jose Fabio.](https://josefabio.com)
+ Donate Monero:
+ `484RLdsXQCDGSthNatGApRPTyqcCbM3PkM97axXezEuPZppimXmwWegiF3Et4BHBgjWR7sVXuEUoAeVNpBiVznhoDLqLV7j`
+ [\[QR\]](https://josefabio.com/figures/monero.jpg)
+- Edited and revised by [Luke](https://lukesmith.xyz).
diff --git a/content/mail/dovecot.md b/content/mail/dovecot.md
new file mode 100644
index 0000000..df2b218
--- /dev/null
+++ b/content/mail/dovecot.md
@@ -0,0 +1,112 @@
+---
+title: "Dovecot Email Server"
+draft: true
+---
+In the article on [SMTP and Postfix](smtp.html), we set up a simple
+Postfix server that we could use to programatically send mail with the
+`mail` command. In order to have a true and fully-functional mail
+server, we need Dovecot, which can store mails received by the server,
+have and authenticate user accounts and interact with mail
+
+## Installation
+
+ apt install dovecot-imapd dovecot-sieve
+
+## Certificate
+
+We will want a SSL certificate for the `mail.` subdomain. We can get
+this with [Certbot](certbot.html). Assuming we are using Nginx for our
+server otherwise, run:
+
+ certbot --nginx certonly -d mail.example.org
+
+## DNS
+
+## Configuring Dovecot
+
+Dovecot\'s configuration file is in `/etc/dovecot/docevot.conf`. If you
+open that file, you will this line: `!include conf.d/*.conf` which adds
+all the `.conf` files in `/etc/dovecot/conf.d/` to the Dovecot
+configuration.
+
+One can edit each of these files individually to get the needed
+configuration, but to make things easy here, delete or backup the main
+configuration file and we will replace it with one single config file
+with all important settings in it.
+
+``` wide
+ssl = required
+ssl_cert = </etc/letsencrypt/live/mail.example.org/fullchain.pem
+ssl_key = </etc/letsencrypt/live/mail.example.org/privkey.pem
+ssl_min_protocol = TLSv1.2
+ssl_cipher_list = EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA256:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EDH+aRSA+AESGCM:EDH+aRSA+SHA256:EDH+aRSA:EECDH:!aNULL:!eNULL:!MEDIUM:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4:!SEED
+ssl_prefer_server_ciphers = yes
+ssl_dh = </usr/share/dovecot/dh.pem
+auth_mechanisms = plain login
+auth_username_format = %n
+
+protocols = $protocols imap
+
+userdb {
+ driver = passwd
+}
+passdb {
+ driver = pam
+}
+
+mail_location = maildir:~/Mail:INBOX=~/Mail/Inbox:LAYOUT=fs
+namespace inbox {
+ inbox = yes
+ mailbox Drafts {
+ special_use = \Drafts
+ auto = subscribe
+}
+ mailbox Junk {
+ special_use = \Junk
+ auto = subscribe
+ autoexpunge = 30d
+}
+ mailbox Sent {
+ special_use = \Sent
+ auto = subscribe
+}
+ mailbox Trash {
+ special_use = \Trash
+}
+ mailbox Archive {
+ special_use = \Archive
+}
+}
+
+service auth {
+ unix_listener /var/spool/postfix/private/auth {
+ mode = 0660
+ user = postfix
+ group = postfix
+}
+}
+```
+
+### Settings Explained
+
+Take a good look at the settings to understand what\'s going on. Some of
+the settings include:
+
+1. SSL settings to allow encrypted connections.
+2. Default directories for a mail account: Inbox, Sent, Drafts, Junk,
+ Trash and Archive.
+3. The mail server will authenticate users against PAM/passwd, which
+ means users you create on the server (so long as they are part of
+ the `mail` group) will be able to receive and send mail.
+4. Create a `unix_listener` that will allow Postfix to authenticate
+ users via Dovecot.
+
+```{=html}
+<!-- -->
+```
+ echo "auth required pam_unix.so nullok
+ account required pam_unix.so" >> /etc/pam.d/dovecot
+
+## Connecting Postfix and Dovecot
+
+[[Next:\<++\>](%3C++%3E)]{.next}
diff --git a/content/mail/opendkim.md b/content/mail/opendkim.md
new file mode 100644
index 0000000..bd8eb5d
--- /dev/null
+++ b/content/mail/opendkim.md
@@ -0,0 +1,187 @@
+---
+title: "Validating your emails with OpenDKIM"
+draft: true
+tags: ['email']
+---
+Email is a lot like real-life mail. You can send email to anyone, but
+you can also write whatever return address you\'d like. That is, it\'s
+pretty easy to pretend to be someone else via mail, and that was
+originally the case with email as well: email is just text, and you
+could just change your `From:` address to any email address you wanted!
+
+DKIM (Domain Keys Identified Mail) helps solve this issue.
+
+OpenDKIM will generate a public/private cryptographic key pair for your
+server. The public key will be made available publicly in your server\'s
+DNS records and the private key will be used to sign every single email
+that leaves the server. This means that people receiving mail from your
+server can now be absolutely sure that it originated from your server
+because their servers can check the cryptographic signature on the email
+with the public key!
+
+OpenDKIM ensures that email originated from the server it claims it did,
+but it does not ensure that it originated from the user account it
+claims it did. This easier problem is solved by server-side
+authorization settings.
+
+## Installation
+
+```sh
+apt install opendkim opendkim-tools
+```
+
+## The Keys and Files
+
+We have to generate the DKIM keys and create some secondary files that
+will be required for our configuration.
+
+### Generate the DKIM key
+
+<!--
+TODO: Make a unique directory for each domain to later allow multiple domain
+DKIM validation for servers serving more than one domain name.
+-->
+
+Here we create directories for the OpenDKIM keys, generate them, and
+ensure they have the right file permissions.
+
+```sh
+mkdir -p /etc/postfix/dkim
+opendkim-genkey -D /etc/postfix/dkim/ -d example.org -s mail
+chgrp opendkim /etc/postfix/dkim/*
+chmod g+r /etc/postfix/dkim/*
+```
+
+### Create the key table
+
+Now we\'ll tell OpenDKIM where the newly generated keys are on the file
+system.
+
+```sh
+echo "mail._domainkey.example.org example.org:mail:/etc/postfix/dkim/mail.private" > /etc/postfix/dkim/keytable
+```
+
+### Create the signing table
+
+```sh
+echo "*@example.org mail._domainkey.example.org" > /etc/postfix/dkim/signingtable
+```
+
+### Adding trusted hosts
+
+```sh
+echo "127.0.0.1
+10.1.0.0/16
+1.2.3.4/24" > /etc/postfix/dkim/trustedhosts
+```
+
+## Configuring opendkim.conf
+
+Now we have all the raw material, so open up `/etc/opendkim.conf` and we
+can finalize our server settings. First, add these lines that will
+source the files we just created.
+
+```yaml
+KeyTable file:/etc/postfix/dkim/keytable
+SigningTable refile:/etc/postfix/dkim/signingtable
+InternalHosts refile:/etc/postfix/dkim/trustedhosts
+
+Canonicalization relaxed/simple
+Socket inet:12301@localhost
+```
+
+There will already be an uncommented `Socket` directive, so delete,
+comment out or replace it with the above.
+
+## Interfacing with Postfix
+
+There are a couple things we must add to the Postfix SMTP server
+settings to interface it with OpenDKIM. Specifically, we have to set our
+OpenDKIM server, which will be running on port `12301`, as a milter
+(mail filter). This is easy to do with the four commands below:
+
+```sh
+postconf -e "milter_default_action = accept"
+postconf -e "milter_protocol = 6"
+postconf -e "smtpd_milters = inet:localhost:12301"
+postconf -e "non_smtpd_milters = inet:localhost:12301"
+```
+
+## Restart and reload Postfix and DKIM
+
+Now that we have all our settings in place:
+
+```sh
+systemctl restart opendkim
+systemctl enable opendkim
+systemctl reload postfix
+```
+
+## Adding the DNS record!
+
+We are only one step away from having functioning OpenDKIM. We must add
+the DKIM public key to our server\'s DNS settings, so go ahead and open
+up [your registrar\'s site](https://www.epik.com/?affid=we2ro7sa6) or
+wherever your site\'s DNS settings are.
+
+The public key is found in the file `/etc/postfix/dkim/mail.txt`, but it
+will display as multiple lines and multiple quoted strings, which is
+annoying and hard to copy-and-paste into your registrar. To make things
+easier, run the following command to format the key in the way we need
+it for the DNS TXT entry:
+
+```sh
+echo -e "
+
+v=DKIM1; k=rsa; $(tr -d "
+" </etc/postfix/dkim/mail.txt | sed "s/k=rsa.* \"p=/k=rsa; p=/;s/\"\s*\"//;s/\"\s*).*//" | grep -o "p=.*")
+
+"
+```
+
+Take the very long output of that command, which will start with
+`v=DKIM1` and add it as a TXT entry in your DNS settings as below. The
+host we put it for is `mail._domainkey`.
+
+{{< img alt="Adding the OpenDKIM TXT entry in DNS settings" src="/pix/dkim-01.png" link="/pix/dkim-01.png" >}}
+
+On my registrar, Epik, this is how it is input, but on some registrars,
+it may be required to include your domain name as well as
+`mail._domainkey.example.org`.
+
+If you have your own DNS server, add a TXT entry as follows:
+
+```txt
+mail._domainkey.example.org TXT v=DKIM1; k=rsa; p=ThatLongRandomSequenceOfLettersAndNumbersOfYours
+```
+
+## Testing it out!
+
+Now we want to send an email to make sure that your emails will now be
+signed with OpenDKIM.
+
+### Hostname
+
+If you\'ve followed these instructions, all emails from the domain
+**example.org** will now have a DKIM signature on them. If we send mail
+via the `mail` command, however, their domain of origin will be whatever
+your server\'s hostname is, which you may have set to something
+different than your domain.
+
+You can permanently change your hostname by changing it in
+`/etc/hostname` and rebooting, or you can just run
+`hostname example.org` to change it temporarily for testing. Either way,
+this will allow us to run the `mail` command as in [the SMTP
+article](smtp.html).
+
+```sh
+echo "Hi there.
+
+This is the text." | mail -s "Email from the server" your@emailaddress.com
+```
+
+### More helpful troubleshooting.
+
+You can also go to [this site](https://appmaildev.com/en/dkim), which
+will help you troubleshoot any other DKIM problems if you mistyped
+something.
diff --git a/content/mail/rainloop.md b/content/mail/rainloop.md
new file mode 100644
index 0000000..f43dbb5
--- /dev/null
+++ b/content/mail/rainloop.md
@@ -0,0 +1,117 @@
+---
+title: "Rainloop"
+tags: ['service']
+icon: 'rainloop.png'
+short_desc: 'A graphical website for accessing a mail server.'
+---
+
+
+[Rainloop](https://www.rainloop.net/)
+is a webmail client, a program that allows you to access your email
+online like Gmail. It is useful to be able to access you email from a
+web browser because it allows you to easily access your email from any
+device with a web browser without any additional setup.
+
+If you set up
+[![logo](/pix/nextcloud.svg)Nextcloud](/nextcloud)
+then you do not need to install Rainloop because Nextcloud comes with a
+webmail client. However, if all you want is a webmail client and you do
+not need all of the extra things that Nextcloud provides, Rainloop would
+be the better choice out of the two since it is less bloated and simpler
+to install.
+
+## Instructions
+
+First we will install the required packages for Rainloop with the
+following command:
+
+```sh
+apt-get install php7.4 php7.4-common php7.4-curl php7.4-xml php7.4-fpm php7.4-json php7.4-dev php7.4-mysql unzip -y
+```
+
+Then we will download the community version of Rainloop, unzip it into
+an appropriate directory and fix all of the file permissions:
+
+```sh
+curl -L "https://www.rainloop.net/repository/webmail/rainloop-community-latest.zip" -o "rainloop.zip"
+unzip rainloop.zip -d /var/www/mail
+chown -R www-data: /var/www/mail
+```
+
+We have installed Rainloop itself, but now we need Nginx to serve the
+client. We do that by adding the following text into the file
+`/etc/nginx/sites-available/mail` (you can replace the bold text with
+whatever is appropriate for your server).
+
+```nginx
+server {
+
+ listen 80;
+
+ server_name mail.example.org ;
+ root /var/www/mail;
+
+ index index.php;
+
+ access_log /var/log/nginx/rainloop_access.log;
+ error_log /var/log/nginx/rainloop_error.log;
+
+ location / {
+ try_files $uri $uri/ /index.php?$query_string;
+ }
+
+ location ~ \.php$ {
+ fastcgi_index index.php;
+ fastcgi_split_path_info ^(.+\.php)(.*)$;
+ fastcgi_keep_conn on;
+ fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
+ include /etc/nginx/fastcgi_params;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+ }
+ location ~ /\.ht {
+ deny all;
+ }
+
+ location ^~ /data {
+ deny all;
+ }
+}
+```
+
+Then enable the site by linking it to the sites-enabled directory:
+
+```sh
+ln -s /etc/nginx/sites-available/mail /etc/nginx/sites-enabled/
+```
+
+Reload nginx:
+
+```sh
+systemctl reload nginx
+```
+
+Finally get certifications if you are using a new subdomain:
+
+```sh
+certbot --nginx
+```
+
+After that go to `mail.example.org/?admin` and login with the default
+username and password: admin, 12345. Now you are in the admin panel and
+the first thing you do should be to change the adminsitrator password by
+looking in the security tab on the left.
+
+{{< img alt="rainloop" src="/pix/rainloop-1.png" >}}
+
+After securing the admin account you can go to domains and add your own
+email address.
+
+{{< img alt="rainloop" src="/pix/rainloop-2.png" >}}
+
+Finally, go to `mail.example.org` and login with your email address and
+password.
+
+## Contribution
+
+[Deniz Telci](https://deniz.telci.org/) - XMR:
+`4AcKbpTUc3QX2zHYdh9HZwJAQyexdybFhF1WhXTFhxAcV9jgzB6kroqGZDgeW3rQqXEMYJioYo61kaLBqstwecty9Bjbr4v`
diff --git a/content/mail/rdns.md b/content/mail/rdns.md
new file mode 100644
index 0000000..6571d8c
--- /dev/null
+++ b/content/mail/rdns.md
@@ -0,0 +1,35 @@
+---
+title: "rDNS and PTR Records"
+draft: true
+tags: ['email']
+---
+While [DNS records](dns.html) refer a domain name to the IP address
+where the the website is hosted, there is also rDNS (reverse DNS) and
+specifically PTR (pointer) records which do the reverse: link a
+server\'s IP to a domain name.
+
+This is important for many things, but especially email. Many email
+servers require that other servers that send them mail have PTR records
+to prevent spam.
+
+## Setting your PTR Record
+
+DNS settings are set with your registrar, while rDNS settings are set
+with your server or VPS provider. **Remember to set records for both
+IPv4 and IPv6!**
+
+In [Vultr](https://www.vultr.com/?ref=8384069-6G) we want to set the
+IPv4 record, click on the server, then \"Settings,\" and make sure the
+\"IPv4\" tab is selected. We can then edit the \"Reverse DNS\" blank
+shown below.
+
+{{< img alt="IPv4 rDNS PTR record set in Vultr" src="/pix/rdns-01.png" >}}
+
+The setting for IPv6 is obviosuly under the IPv6 tab. Note here that we
+copy the full IPv6 address from above and create a new rDNS entry by
+pasting that and the domain name in the blanks below. Then just select
+\"Add.\"
+
+{{< img alt="IPv6 rDNS PTR record set in Vultr" src="/pix/rdns-02.png" >}}
+
+That\'s it!
diff --git a/content/mail/smtp.md b/content/mail/smtp.md
new file mode 100644
index 0000000..6ce92f2
--- /dev/null
+++ b/content/mail/smtp.md
@@ -0,0 +1,70 @@
+---
+title: "Setting up a Postfix SMTP server"
+draft: true
+---
+The first step to setting up an email server is having an SMTP server.
+SMTP sends and receives email. Whether we want a full email server or
+just the ability to send automated email by script, we will need SMTP,
+and Postfix is the standard SMTP server.
+
+Here let\'s set a server up. Note that our goal is to be able to send
+emails from our server. If you want a full email server, this is the
+first step, and we will address the rest later.
+
+## Before beginning!
+
+Whatever VPS ([Vultr](https://www.vultr.com/?ref=8384069-6G) or
+[Frantech](https://my.frantech.ca/aff.php?aff=3886)) or IPS you are
+using, it is a very common policy to **automatically block all email
+ports by default**. VPS providers do this to prevent spammers from using
+their services.
+
+If you want to start an email server, therefore, go to your VPS\'s site
+and open a ticket or make a request to open up email ports. This is a
+simple process that requires nothing too special. One of the wagies at
+your VPS will kindly do the needful and open your ports for you. Note
+that this is not the same as unblocking a port with [ufw](ufw.html).
+
+## Installation
+
+First, we install Postfix and also `mailutils`, which comes with some
+mail programs we will use.
+
+ apt install -y mailutils postfix
+
+Installing Postfix for the first time will give us some graphical
+options.
+
+![SMTP Postfix internet site choice](pix/smtp-01.png)
+
+When asked for a \"mail name\", give your full domain name from which
+you would like mail to come and go, e.g. [example.org]{.dfn} or
+[landchad.net]{.dfn}.
+
+![SMTP Postfix fully qualified domain name](pix/smtp-02.png)
+
+## Test the email
+
+That is actually all you need to have set up to have a barebones,
+send-only email server. We can test our server by running a `mail`
+command like that below.
+
+ echo "Hi there.
+
+ This is the text." | mail -s "Email from the server" your@emailaddress.com
+
+And that is simply enough the command your server can run to send mail.
+Note that we use the `-s` option to specify the email\'s subject while
+we pipe the email content into the `mail` command via standard input. In
+this example I use a quoted multiline email as an example.
+
+## Do you see your message?
+
+If you sent the above test message to an account on Gmail or another
+major email provider, there is **very high** chance of the message you
+sent above being marked as spam or not appearing at all!
+
+Don\'t worry, we\'ll take care of that in the next two articles where we
+set up rDNS and OpenDKIM to validate the emails you send.
+
+[[Next: rDNS and PTR Records](rdns.html)]{.next}
diff --git a/content/maintenance.md b/content/maintenance.md
new file mode 100644
index 0000000..545da82
--- /dev/null
+++ b/content/maintenance.md
@@ -0,0 +1,124 @@
+---
+title: "Maintaining a Server"
+date: 2021-06-29
+tags: ['server']
+---
+Here are some important topics you should be familiar with whenever you
+are managing a server.
+
+## Keep packages up to date. {#update}
+
+All GNU/Linux distributions use package managers to easily be able to
+install and update packages without manually downloading them. On
+Debian, which we use here for these tutorial the package manager is
+`apt-get` or `apt` for short.
+
+It\'s a good idea to use `apt` to keep your software reasonably up to
+date.
+
+```sh
+apt update
+apt upgrade
+```
+
+Not only do up-to-date packages often come with more features, but they
+can also fix any possible security bugs.
+
+## Troubleshooting general problems
+
+Often when you are installing something new, you might miss a step and
+run into an error, so it\'s important to know how to check and see what
+errors have happened on your computer.
+
+On Debian and other GNU/Linux distributions that use systemd (most of
+them), you can use the command `journalctl` to look at the system\'s
+general log. You will probably want to run `journalctl -xe` as the `-x`
+and `-e` as that gives the most information and starts you at the bottom
+of the log to see the most recent errors.
+
+Some programs do not use this system log, but have their own logs stored
+in `/var/log/`, or sometimes it\'s more convenient to look at a specific
+program\'s log to see only its issues.
+
+For example, we can see that in `/var/log/nginx/`, nginx produces both
+`error` and `access` files. The `access` files show you all the times
+people connect to files on your server and much more. We can look at the
+most recent errors by running:
+
+```sh
+tail -n 25 /var/log/nginx/error.log
+```
+
+The command `tail -n 25` means \"show me the last 25 lines of this
+file.\" You can replace that with `less` to browse the whole file. In
+`less`, navigate with arrows or vim-keys and exit with `q`.
+
+### systemctl
+
+Another tool on systemd distributions is `systemctl`. At a basic level,
+use `systemctl status put-service-name-here` to see if a system service
+is running and its most recent log. But there\'s much more to
+`systemctl`.
+
+For example, you can run `systemctl stop nginx` to stop NginX and
+`systemctl start nginx` to start it back up (or use `restart` for both).
+When you make changes to a program\'s configuration files, `reload` well
+make them reload them. If you no longer want a service to start when the
+system is rebooted, use `disable`, or conversely, to make a service
+start on reboot use `enable`.
+
+## Finding Files
+
+Especially if you\'re new to how a GNU/Linux system is arranged, you
+might need help finding files. To find program-related files, you can
+just use `whereis`:
+
+```sh
+$ whereis nginx
+nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx /usr/share/man/man8/nginx.8.gz
+```
+
+This command lists the directories related to that program. For example,
+`/etc/nginx` is where the configuration files are and `/usr/share/nginx`
+is where the library and module-like files are.
+
+But `whereis` can be used only with installed programs. A more general
+tool is the pair of `updatedb` and `locate`.
+
+`updatedb` is a command that quickly indexes every file and directory on
+your computer. Then you can run `locate` to find a file containing a
+given name. After running `updatedb`, try running `locate nginx` to find
+all files with \"nginx\" in their name.
+
+You can make your search more specific by chaining other Unix commands
+through pipes. For example, `grep` takes input and returns only lines
+that match an extra argument. In the example below, we `locate` all
+files with \"nginx\" in the name, but we use `grep` to only show us
+those with the word \"available\" in them.
+
+```sh
+root@landchad:~# locate nginx | grep available
+/etc/nginx/modules-available
+/etc/nginx/sites-available
+/etc/nginx/sites-available/default
+/etc/nginx/sites-available/landchad
+/usr/share/nginx/modules-available
+/usr/share/nginx/modules-available/mod-http-auth-pam.conf
+/usr/share/nginx/modules-available/mod-http-dav-ext.conf
+/usr/share/nginx/modules-available/mod-http-echo.conf
+/usr/share/nginx/modules-available/mod-http-geoip.conf
+/usr/share/nginx/modules-available/mod-http-image-filter.conf
+/usr/share/nginx/modules-available/mod-http-subs-filter.conf
+/usr/share/nginx/modules-available/mod-http-upstream-fair.conf
+/usr/share/nginx/modules-available/mod-http-xslt-filter.conf
+/usr/share/nginx/modules-available/mod-mail.conf
+/usr/share/nginx/modules-available/mod-stream.conf
+```
+
+`updatedb` is an ideal candidate for a [cronjob](/cron) so you
+don\'t have to worry about running each time. For example, adding the
+following to your crontab will run `updatedb` every 30 minutes:
+
+```sh
+*/30 * * * * /usr/bin/updatedb
+```
diff --git a/content/matrix.md b/content/matrix.md
new file mode 100644
index 0000000..4442cc3
--- /dev/null
+++ b/content/matrix.md
@@ -0,0 +1,139 @@
+---
+title: "Matrix Synapse"
+date: 2021-07-16
+icon: 'element.svg'
+tags: ['service']
+short_desc: "An encrypted chat server sleek and accessible even to normies."
+---
+
+Matrix is easy-to-use, decentralized and encrypted private chat
+software. Matrix is federated, meaning that with a Matrix account on any
+server, including your own, you can talk to any other Matrix account on
+the internet, similar to email. Matrix also allows fully end-to-end
+encrypted group chats.
+
+**Synapse** is the name of the default Matrix server. It is written in
+Python. While it is requires somewhat more system resources than [an
+XMPP server](/prosody), it makes up for that in being very accessible
+to non-technical users.
+
+## Installation
+
+Synapse is not in the Debian package repositories by default, but we can
+easily add Matrix\'s repository including it:
+
+```sh
+apt install -y lsb-release wget apt-transport-https
+wget -O /usr/share/keyrings/matrix-org-archive-keyring.gpg https://packages.matrix.org/debian/matrix-org-archive-keyring.gpg
+echo "deb [signed-by=/usr/share/keyrings/matrix-org-archive-keyring.gpg] https://packages.matrix.org/debian/ $(lsb_release -cs) main" > /etc/apt/sources.list.d/matrix-org.list
+```
+
+After we update our packages lists, we will be able to install Synapse
+with `apt`.
+
+```sh
+apt update
+apt install matrix-synapse-py3
+```
+
+When prompted, give your main domain name (not a subdomain). This will
+be the domain appended to your Matrix address, e.g.
+`@chad:landchad.net`.
+
+## Nginx configuration
+
+Create an Nginx configuration file for Matrix, say
+`/etc/nginx/sites-available/matrix` and add the content below:
+
+```nginx
+server {
+ server_name matrix.example.org ;
+ listen 80;
+ listen [::]:80;
+ location / {
+ proxy_pass http://localhost:8008;
+ }
+ location ~* ^(\/_matrix|\/_synapse\/client) {
+ proxy_pass http://localhost:8008;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ client_max_body_size 50M ;
+ }
+ location /.well-known/matrix/server {
+ return 200 '{"m.homeserver": {"base_url": "https://matrix.example.org"}}';
+ default_type application/json;
+ add_header Access-Control-Allow-Origin *;
+ }
+}
+```
+
+Note the `client_max_body_size` variable. By default, Nginx caps the
+size of files it can transfer. We increase that to 50M if needed by
+Matrix. (Note however that both Matrix and Nginx have seperate settings
+for this and to raise it to something much larger, you will have to
+increase the value in both configuration files.)
+
+Now let\'s enable the Nginx Matrix site and reload Nginx to make it
+active.
+
+```sh
+ln -s /etc/nginx/sites-available/matrix /etc/nginx/sites-enabled
+systemctl reload nginx
+```
+
+### Encryption
+
+Obviously, we need to encrypt our `matrix` subdomain as well. Let\'s do
+that with certbot:
+
+```sh
+certbot --nginx -d matrix.example.org
+```
+
+## Configuration
+
+### Read the config file
+
+The configuration file for Matrix is in
+`/etc/matrix-synapse/homeserver.yaml`. It is well documented and
+commented, so you can read about the settings, but let\'s change the
+essential ones here.
+
+Make what changes you want and run `systemctl reload matrix-synapse` to
+make the system configuration active.
+
+### Create an administrator account
+
+If you allow open registration on your server in the configuration file,
+you can create an account through Element or another Matrix client, but
+you are probably going to want an official admin account to use. To make
+one, simply run the following command, which will then give you several
+choices for creating a user, among which will be the ability to make it
+an admin.
+
+```sh
+register_new_matrix_user -c homeserver.yaml http://localhost:8008
+```
+
+## Using Matrix with ![Element Matrix logo](pix/element.svg)Element
+
+There are many different [clients](https://matrix.org/clients/) that can
+be used on desktops or phones to chat on your Matrix server, but the
+most popular and most widely vetted is ![Element
+logo](pix/element.svg)Element.
+
+Get Element to access your Matrix server:
+
+- Mobile:
+ - [F-droid](https://f-droid.org/packages/im.vector.app/)
+ - [Google
+ Play](https://play.google.com/store/apps/details?id=im.vector.app)
+ - [Apple App
+ Store](https://apps.apple.com/app/vector/id1083446067)
+- Real computer:
+ - GNU/Linux: You know how to install it.
+ - [Windows](https://packages.riot.im/desktop/install/win32/x64/Element%20Setup.exe)
+ - [Mac](https://packages.riot.im/desktop/install/macos/Element.dmg)
+
+Note also that Element has a web client (i.e. a version that can be
+accessed on your own website) that is also easy to install on an Nginx
+server, although that will be covered in another article.
diff --git a/content/monero.md b/content/monero.md
new file mode 100644
index 0000000..87f1d78
--- /dev/null
+++ b/content/monero.md
@@ -0,0 +1,89 @@
+---
+title: "Monero"
+icon: 'xmr.svg'
+date: '2021-06-29'
+tags: ['service']
+short_desc: "The ideal private cryptocurrency for the Internet."
+---
+Monero (abbreviated XMR) is easily the cryptocurrency most actually used
+as such. Unlike Bitcoin, Monero is actually private and has very low
+transaction fees. That makes it a good idea to get a Monero wallet and
+add an address on your website where you can receive donations.
+
+## Generate a Monero wallet
+
+Go to [Monero\'s official site](https://www.getmonero.org/downloads/) and you can download either the GUI (graphical) or CLI (command-line
+wallet). Some Linux distributions will have these packages in their
+repositories (`monero` and `monero-gui` on Arch-based distributions).
+
+<aside>
+
+If you are a Windows user, note that you will *probably* get some kind
+of warning that you are installing something malicious. This is because
+many malicious pieces of software include crypto miners in them. This
+wallet, obviously, does include one as well, because it has the ability
+to mine if you want. You can disregard these messages and as that
+official site mentions, you can follow their directions to check the
+integrity of the download with SHA256.
+
+</aside>
+
+Once you install and run the wallet program, you will get a menu like
+this:
+
+{{< img src="/pix/monero-01.png" alt="simple mode" >}}
+
+Now if you want to start using Monero and using it as a pro, you can
+choose to download the whole blockchain which will maximize your
+transactional privacy, however for this tutorial or setting up a wallet,
+we can just do the Simple Mode and save our bandwidth. **In fact, if you
+are paranoid, you can disconnect your computer from the internet while
+generating a wallet.**
+
+Now we choose to create a wallet.
+
+{{< img src="/pix/monero-02.png" alt="create wallet" >}}
+
+Now we get the most important and sensitive part, you private mneumonic
+seed. **These words are sacred! They are your money!** To be clear, they
+are randomly generated words that seed the randomness required to unlock
+whatever money you receive or hold. Never show these words to anyone,
+don\'t even keep them on your computer, but write them down and store
+them securely in real life in a safe or somewhere where only you have
+access.
+
+{{< img src="/pix/monero-03.png" alt="seed" >}}
+
+It goes without saying that the seed above that we generated for this
+tutorial should never be used by anyone since it is public on the
+internet and anyone could easily take the funds from the wallet.
+
+Finally, we get to the main wallet screen. Now we see your public
+sharable wallet receiving address. It is the thing that starts with `4`
+and is too long to be included in the image below labeled \"Primary
+address.\"
+
+{{< img src="/pix/monero-04.png" alt="address" >}}
+
+Click the clipboard next to it to copy the whole sequence (which will be
+more than 90 letters and numbers) to your clipboard. This is your
+address. Put it on your website and you can receive donations!
+
+You can also click to save that QR code image and you can put it up on
+your website and people will be able to scan it and send you Monero.
+When scanned, that QR code will read as the public donation address.
+
+## What do I do now?
+
+You can now receive Monero/XMR donations! All you need to do is put
+either your full address or your QR code on your site and people can
+send you tips in Monero.
+
+Here is the address we use for this site (i.e. not the compromised
+wallet generated above):
+
+<code class=crypto>84RXmrsE7ffCe1ADprxLMHRpmyhZuWYScDR4YghE8pFRFSyLtiZFYwD6EPijVzD3aZiEpg57MfHEr1pGJNPXyJgENMnWrSh</code>
+
+{{< img src="/pix/xmr.png" class=qr alt="monero donation qr" >}}
+
+It\'s now up to you how and where to display these on your site.
diff --git a/content/movim.md b/content/movim.md
new file mode 100644
index 0000000..8743b81
--- /dev/null
+++ b/content/movim.md
@@ -0,0 +1,116 @@
+---
+title: "Movim"
+draft: true
+icon: 'movim.svg'
+tags: ['service']
+short_desc: 'An XMPP-based social media site, blog and chat site.'
+---
+## Installing the Packages and Database
+
+### Dependencies
+
+ apt install -y nginx python3-certbot-nginx postgresql composer php-fpm php-curl php-mbstring php-imagick php-gd php-pgsql php-xml git
+
+### Installing Movim Itself
+
+ cd /var/www
+ git clone https://github.com/movim/movim.git
+ cd movim
+ composer install
+
+### Preparing Permissions
+
+ cd /var/www
+ chown www-data movim && chown www-data movim/public && chmod u+rwx movim
+
+### Database setup
+
+ su - postgres # Become the postgres user
+ psql # Open a postgresql prompt
+ CREATE USER movim WITH PASSWORD 'yourpassword' ;
+ CREATE DATABASE movim WITH OWNER movim ;
+ \q
+
+leave postgres user
+
+We now have to tell movim to use this newly created postgresql username
+and database that we\'ve created. Create a new file in
+`/var/www/movim/config/db.inc.php` and add the following content:
+
+ <?php
+ $conf = [
+ 'type' => 'pgsql',
+ 'username' => 'movim',
+ 'password' => 'yourpassword',
+ 'host' => 'localhost',
+ 'port' => 5432,
+ 'database' => 'movim'
+ ];
+
+ask for pass https://movim.yourdomain.com Choose postgresq localhost
+pass
+
+## Configuration with nginx
+
+Let\'s create an nginx configuration file for this movim site. I will
+create a file `movimsite.conf` in `/etc/nginx/sites-available/` and add
+the following content:
+
+ server {
+ listen 80 ;
+ listen [::]:80 ;
+ server_name movim.lukesmith.xyz ;
+ include /etc/nginx/snippets/movim.conf ;
+ location / {
+ try_files $uri $uri/ =404;
+ }
+ }
+
+Note above that this is calling the file
+`/etc/nginx/snippets/movim.conf` which contains the content needed for
+Movim and should be autocreated when installing the Debian package.
+
+To enable the site, let\'s link the file to the `sites-enabled`
+directory and then reload nginx to update it.
+
+ ln -s /etc/nginx/sites-available/movimsite.conf /etc/nginx/sites-enabled/
+ systemctl reload nginx
+
+Now, run [certbot](/basic/certbot) which we installed above to get secured
+connections on your site. Choose to \"Redirect\" unencrypted connections
+when prompted.
+
+ certbot --nginx
+
+## Systemd service
+
+Let\'s create a systemd service for Movim. Create the file
+`/etc/systemd/system/movim.service` and add the content below:
+
+ [Unit]
+ Description=Movim daemon
+ After=nginx.service network.target local-fs.target
+
+ [Service]
+ User=www-data
+ Type=simple
+ Environment=PUBLIC_URL=https://localhost/movim/
+ Environment=WS_PORT=8080
+ EnvironmentFile=-/etc/default/movim
+ ExecStart=/usr/bin/php daemon.php start --url=${PUBLIC_URL} --port=${WS_PORT}
+ WorkingDirectory=/var/www/movim/
+ StandardOutput=syslog
+ SyslogIdentifier=movim
+ PIDFile=/run/movim.pid
+ Restart=on-failure
+ RestartSec=10
+
+ [Install]
+ WantedBy=multi-user.target
+
+ systemctl daemon-reload
+ systemctl restart movim
+
+Install prosody modules apt install mercurial mkdir -p
+/usr/share/prosody hg clone https://hg.prosody.im/prosody-modules/
+/usr/share/prosody/modules
diff --git a/content/networking.md b/content/networking.md
new file mode 100644
index 0000000..5effd8a
--- /dev/null
+++ b/content/networking.md
@@ -0,0 +1,340 @@
+---
+title: Networking Basics
+date: 2022-07-01
+tags: ['concepts']
+---
+
+## A quick detour to binary
+
+You probably know that everything computers do, they do in binary
+(zeroes and ones) under the hood. But how does that actually work?
+
+Binary is just another numbering system like decimal (there are many
+others!), so while with decimal each digit can have 10 different values
+(0-9, hence **deci**mal), numbers represented in binary have 2 possible
+values (0-1, hence **bi**nary). In binary a digit is called a bit.
+
+What is the highest number you can represent with one digit in decimal?
+Easy: 9. So how many different values are there? 10 (0-9).
+
+What about 2 digits? 99 and 100, respectively. 3 digits? 999 and 1000.
+I\'m sure I don\'t need to bore you by continueing.
+
+### The maths behind it
+
+Can we define a formula for the amount of possible values a decimal
+number with `n` digits can have?
+
+It\'s pretty easy: `10n`.
+
+Now the 10 there in a numbering system where each digit can have 10
+different values can\'t be a coincidence!
+
+So we can generalize: In a numbering system where each digit can have
+`x` different values, the amount of possible values for a number with
+`n` digits is `xn`.
+
+So how many different values can we represent with 8 Bits (1 Byte)?
+`28 = 256` (0-255).
+
+The IPv4 addresses you know are 32 bits long. So how many computers
+could we theoretically assign unique IPs to on the internet?
+`232 = 4,294,967,296`. That\'s 4 Billion! However there are far more
+computers than that on the internet now, which is why people had to come
+up with hacks (which we\'ll talk about later) so that we can today still
+predominantly use pretty IPv4, as opposed to that ugly new IPv6 (eww).
+
+We\'ll say \"IP address\" instead of \"IPv4 address\" from here on.
+
+By the way, this principle goes a long way in computing! Say, for
+example, I know your password is 7 letters long and contains only
+lowercase english letters (a-z). How many times would I have to guess at
+maximum to crack your password? `257 = 6,103,515,625` times.
+
+### Converting from binary to decimal
+
+You can use the same principle to convert from one numbering system to
+another. Each digit gains \"significance\", starting at zero going from
+right to left. This is easiest understood through an example from
+decimal:
+
+```
+943 = 9*102 + 4*101 + 3*100 = 900 + 40 + 3 = 943
+```
+
+The same holds true for binary:
+
+```
+11001101 = 27 + 26 + 23 + 22 + 20 = 128 + 64 + 8 + 4 + 1 = 205
+```
+
+### The binary behind IP addresses
+
+As mentioned, IP addresses are made up of 32 bit, or 4 byte. IP
+addresses are usually represented in \"dotted-decimal\" notation, where
+we write the decimal value of the first byte (left-to-right), a dot,
+then the decimal value of the second byte, etc.
+
+So, in theory, the lowest possible IP address is `0.0.0.0` (all bits are
+0) and the highest possible IP address is `255.255.255.255` (all bits
+are 1).
+
+## Subnetting
+
+Open up a terminal and run
+
+```sh
+ip a
+```
+
+You should see many names, such as `wlan*` or `wlp*` for wireless
+interfaces or something like `eth*` or `enp*` for ethernet interfaces.
+I\'ve used a new word here: \"interfaces\", we\'ll talk more about what
+those are later.
+
+Here\'s my WiFi interface:
+
+{{< img alt="wifi interface" src="/pix/networking-wlan0.png" link="/pix/networking-wlan0.png" >}}
+
+We can see an IP address, `192.168.1.221`, and another one which we\'ll
+ignore for now. Did I just leak my IP address? No, it is only my local
+IP, it could even be that yours is the same as mine!
+
+There are two reasons for this:
+
+1. There is a [list of IP address
+ ranges](https://en.wikipedia.org/wiki/Reserved_IP_addresses#IPv4)
+ reserved for you to use however you want, here in local networking.
+ You will not find a server on the internet that has an IP in one of
+ those ranges.
+2. The hack to get around the limitations of IPv4 I mentioned earlier
+ is [NAT (Network Address
+ Translation)](https://en.wikipedia.org/wiki/Network_address_translation).
+ Your router gives every device in your local network one of those
+ reserved IPs and manages one public IP towards the internet for all
+ of them. So instead of every device needing one of those 4 Billions
+ IPs, only every house needs one. And some ISPs take this a level
+ further and again put multiple houses under one NAT, so multiple
+ houses can share one IP towards the internet (Carrier-Grade NAT).
+
+If you followed the link for reserved IP address ranges or looked closer
+at my screenshot, you will see IP addresses followed by a slash and then
+some number, here `/24`. This is how we denote IP ranges in networking,
+the so-called CIDR-Notation. The first ip address in the range is the
+**Network ID** and the number after the slash is the **subnet mask**. It
+might look strange at first, but makes a lot of sense: The subnet mask
+is the amount of bits **fixed**. So here in my case the first 24 bits (3
+bytes) are fixed and my local network\'s IP range, also called
+**subnet**, goes from `192.168.1.0` to `192.168.1.255`.
+
+Here are two popular reserved subnets and their IP ranges:
+
+```
+192.168.0.0/16: 192.168.0.0 – 192.168.255.255
+10.0.0.0/8: 10.0.0.0 – 10.255.255.255
+```
+
+Here\'s another popular one, but note that the subnet mask isn\'t
+divisible by 8, so it is a bit less easy to deal with:
+
+```
+172.16.0.0/12: 172.16.0.0 – 172.31.255.255
+```
+
+The way this works is the first byte is fully fixed, and then the first
+4 bits of the second byte are fixed too, the rest is usable by us. So in
+the second byte the last `8-4 = 4` bits are free. `24 = 16`, giving us
+the actual highest number 15. We add this to the \"starting point\", the
+current value of the second byte, and arrive at `16+15 = 31`!
+
+Don\'t worry if that last part about uneven subnet-masks was confusing
+to you, you won\'t have to deal with them as a regular user.
+Additionally there are websites where you can enter subnets and they do
+the maths for you.
+
+## Interfaces
+
+I\'ve mentioned interfaces a few times now without really explaining
+what they are. Generally you can think of interfaces as physical
+networking devices. If you have a WiFi-Card in your computer, it will
+get an interface. If you have an ethernet card, it will get another one.
+If you now plug in something like a USB WiFi dongle, it will get another
+interface.
+
+There are also virtual interfaces. For example if you run a virtual
+machine with something like virt-manager, use containers with docker or
+connect to a VPN through OpenVPN or WireGuard, all those get virtual
+interfaces.
+
+We can assign IP addresses to interfaces and Linux then knows that when
+it receives a packet who\'s recipient is that IP, it is meant for us.
+Then later with routing we can tell Linux to send packets destined to,
+say, `192.168.3.0/24`, to our ethernet interface, which will make Linux
+send that data to the ethernet card, which will in turn send it through
+the actual physical cable!
+
+Here\'s a bigger picture of the full output of `ip a` on my machine:
+
+{{< img alt="output of ip a" src="/pix/networking-interfaces.png" link="/pix/networking-interfaces.png" >}}
+
+We can see a few interfaces here:
+
+- `lo`: The loopback interface. A virtual interface that makes packets
+ to `127.0.0.1` go straight back to your own machine.
+- `wlan0`: My WiFi interface. We can see its state is `UP`, I have the
+ IP `192.168.1.221` on the network and the subnet mask is `/24`.
+- `virbr0`: My KVM interface. We can see its state is `DOWN`, I have
+ the IP `192.168.122.1` on the network and the subnet mask is `/24`.
+- `wgpi`: An interface for the WireGuard connection I have to my
+ Raspberry Pi. I have the IP `10.91.0.2` on the network and the
+ subnet mask is `/24`.
+- `wgnord`: An interface for the WireGuard connection I have to a
+ remote VPN server. I have the IP `10.5.0.2` on the network and the
+ subnet mask is `/32`.
+
+## Routing
+
+Okay, so we\'ve learned about interfaces now. Those don\'t do much by
+themselves though, since right now Linux will never really use them. To
+make use of them we need to use routing to tell Linux which packets it
+should put into those interfaces. These definitions of what outgoing
+traffic to put into which interfaces are called routes!
+
+To view the routes set up on your machine, run this command:
+
+```sh
+ip r
+```
+
+Here\'s the command\'s output on my server:
+
+{{< img alt="output of ip r" src="/pix/networking-server-routes.png" link="/pix/networking-server-routes.png" >}}
+
+And here\'s an excerpt of the interfaces on my server:
+
+{{< img alt="network interface" src="/pix/networking-server-interfaces.png" link="/pix/networking-server-interfaces.png" >}}
+
+The first route containing `default via` is special: All packets that
+don\'t match other routes are automatically sent to this interface
+(`ens3`). Now you might remember `172.31.1.1` is in one of those
+reserved subnets, so this isn\'t another machine on the internet! This
+is my server\'s \"gateway\". At home your gateway probably is your
+router: You send everything to it and it then forwards those packets to
+the internet (or another device on your local network, if you\'re
+speaking to another IP within your subnet).
+
+Note also that my server\'s `ens3` interface has an IP address assigned
+which is not one of the reserved ones. Therefore my server isn\'t behind
+NAT and this is the actual IP my server can be reached at on the
+internet! Also note that the subnet mask is `/32`, or \"all bits in this
+IP are fixed\".
+
+The second line is for the virtual interface created by docker. All
+containers get assigned an IP within the subnet `172.17.0.0/16`, and
+this route tells Linux to put packets destined for said subnet into the
+`docker0` virtual interface, which then ends up at the container having
+that IP. We can see some additional info too: The IP packet\'s source
+will be set to `172.17.0.1` and the `linkdown` state signifies that we
+have a route set up, but the interface for that route is in `DOWN`
+state.
+
+## Putting it all into practice
+
+Now it might be interesting and all to know how Linux does networking,
+but as a regular user you\'ve probably never had to touch the `ip`
+command in the past: Your server comes set up out of the box and if you
+connect to a WiFi, the interface and routes are configured automatically
+for you. This is done by your network manager through
+[DHCP](https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol).
+
+Recently I\'ve had a use case where I had to configure networking
+manually: I wanted to move around 200GB of data from one laptop to
+another. Now there are a few ways I could go about this: I could look
+for a big enough USB-Drive and move the data that way. Or I could
+connect both devices to the same WiFi (they already were) and move the
+data over the network using rsync, or sshfs, or scp, or nfs, \... But
+the problem here is that my local WiFi is only about 100Mbit/s fast,
+moving 200GB at that speed would take over 4 hours, if my math is
+correct, and would congest the WiFi for all that time. But your standard
+ethernet can do a stable 1Gbit/s, which would drop the time down to 26
+minutes!
+
+So I take an ethernet cable and directly connect both laptops with that.
+On both machines `ip a` now shows something like this:
+
+{{< img alt="new output of ip a" src="/pix/networking-ethernet-unconfigured.png" link="/pix/networking-ethernet-unconfigured.png" >}}
+
+There is no DHCP-Server running on either machine, so we\'ll have to do
+the configuring ourselves! From here on we\'ll have Computer A with
+interface `eth0` and Computer B with interface `eth1`, for clarity.
+
+First we must choose what subnet our ethernet interface should use. We
+can freely choose from the list of reserved subnets here, as long as the
+subnet isn\'t occupied by another interface on either machine. We\'ll
+say `192.168.50.0/24`.
+
+Note also that the first and last address on each subnet, here
+`192.168.50.0` and `192.168.50.255`, respectively, can\'t actually be
+assigned to any device. The first is called \"Network ID\", as mentioned
+previously, and the last is called \"broadcast IP\".
+
+So we\'ll give Computer A the IP `192.168.50.1` and Computer B the IP
+`192.168.50.2`. To do that we use the `ip` command aswell.
+
+Computer A:
+
+```sh
+ip addr add 192.168.50.1/24 dev eth0
+```
+
+Computer B:
+
+```sh
+ip addr add 192.168.50.2/24 dev eth1
+```
+
+It should look something like this now:
+
+{{< img alt="new ip addresses" src="/pix/networking-ethernet-ip.png" link="/pix/networking-ethernet-ip.png" >}}
+
+Now we change the interface\'s state to `UP`:
+
+Computer A:
+
+```sh
+ip link set eth0 up
+```
+
+Computer B:
+
+```sh
+ip link set eth1 up
+```
+
+It should look something like this now:
+
+{{< img alt="ethernet output" src="/pix/networking-ethernet-ip-up.png" link="/pix/networking-ethernet-ip-up.png" >}}
+
+Are we done? You can try pinging one IP from another. It won\'t work,
+because we don\'t have routes set up yet. So lets\'s do that:
+
+Computer A:
+
+```sh
+ip route add 192.168.50.0/24 dev eth0
+```
+
+Computer B:
+
+```sh
+ip route add 192.168.50.0/24 dev eth1
+```
+
+You should see something like this in `ip r`:
+
+{{< img alt="ip routes final" src="/pix/networking-ethernet-route.png" link="/pix/networking-ethernet-route.png" >}}
+
+They are now able to talk to each other!
+
+## Contribution
+- [phire](https://phire.cc)
diff --git a/content/nextcloud.md b/content/nextcloud.md
new file mode 100644
index 0000000..4d571cc
--- /dev/null
+++ b/content/nextcloud.md
@@ -0,0 +1,292 @@
+---
+title: "Nextcloud"
+date: 2021-06-30
+icon: 'nextcloud.svg'
+tags: ['service']
+short_desc: 'A free and private Google Drive-like cloud storage system.'
+---
+
+## What is Nextcloud? {#whatis}
+
+[![](/pix/nextcloud.svg)Nextcloud](https://nextcloud.com)
+is a free and open source solution for cloud storage. However it can
+also do other things, such as manage your email, notes, calender, tasks,
+and can even connect to the Fediverse (think Mastodon and Pleroma).
+Pretty much every service that Google has to offer has a much better
+alternative as a Nextcloud app and this is a must-have for anyone
+wanting to get away from Google services but still wants a traditional
+cloud experience (in the likes of Google Services, anyways).
+
+## Instructions
+
+We should upgrade the system and then install packages that we might
+need. Run the following command:
+
+```sh
+apt full-upgrade -y && apt install mariadb-server php-mysql php php-gd php-mbstring php-dom php-curl php-zip php-simplexml php-xml php-fpm -y
+```
+
+Next, we need to set up our SQL database by running a Secure
+Installation and creating the tables that will store data that Nextcloud
+will need. Run the following command:
+
+```sh
+mysql_secure_installation
+```
+
+When it asks for root a password, say yes and input a new and secure
+password. The root password here is just for the SQL database, not for
+the GNU/Linux system.
+
+Answer the rest of the questions as follows:
+
+```sh
+Remove anonymous users? [Y/n]: Y
+Disallow root login remotely? [Y/n]: Y
+Remove test database and access to it? [Y/n]: Y
+Reload privilege tables now? [Y/n]: Y
+```
+
+
+Next, sign into the SQL database with the new and secure password you
+chose before. Run the following command:
+
+```sh
+mysql -u root -p
+```
+
+We need to create a database for Nextcloud. Follow the instructions
+below and change some of the placeholders as you wish:
+
+```mysql
+CREATE DATABASE nextcloud;
+GRANT ALL ON nextcloud.* TO 'username'@'localhost' IDENTIFIED BY 'password';
+FLUSH PRIVILEGES;
+EXIT;
+```
+
+Now we need to configure PHP. Let\'s start my making sure that the PHP
+user is set to `www-data` and if that is not the case, add the
+`www-data` user if needed and set the correct variable in `nginx.conf`.
+Make sure this line is at the beginning of `/etc/nginx/nginx.conf`.
+
+```nginx
+user www-data;
+```
+
+Check for the `www-data` user by running `id -u www-data`. If a number
+is output from that command, then the www-data user exists. If not. add
+the user simply by running `useradd www-data`
+
+Next, we need to ensure that we have SSL certificates generated for your
+website. If you have not already done this, refer to [this
+guide](/basic/certbot).
+
+In `/etc/nginx/sites-available/` we need to make a new configuration for
+Nextcloud (example: `/etc/nginx/sites-available/nextcloud`). Create it
+and open it, modify, and add the following lines:
+
+```nginx
+upstream php-handler {
+ server unix:/var/run/php/php7.4-fpm.sock;
+ server 127.0.0.1:9000;
+}
+
+server {
+ listen 80;
+ listen [::]:80;
+ server_name example.org;
+
+ return 301 https://$server_name$request_uri;
+}
+
+server {
+ listen 443 ssl http2;
+ listen [::]:443 ssl http2;
+ server_name example.org;
+ ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem ;
+ ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem ;
+
+ root /var/www;
+
+ location = /robots.txt {
+ allow all;
+ log_not_found off;
+ access_log off;
+ }
+
+ location ^~ /.well-known {
+ location = /.well-known/carddav { return 301 /nextcloud/remote.php/dav/; }
+ location = /.well-known/caldav { return 301 /nextcloud/remote.php/dav/; }
+
+ location /.well-known/acme-challenge { try_files $uri $uri/ =404; }
+ location /.well-known/pki-validation { try_files $uri $uri/ =404; }
+
+ return 301 /nextcloud/index.php$request_uri;
+ }
+
+ location ^~ /nextcloud {
+ client_max_body_size 512M;
+ fastcgi_buffers 64 4K;
+
+ gzip on;
+ gzip_vary on;
+ gzip_comp_level 4;
+ gzip_min_length 256;
+ gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
+ gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
+
+ add_header Referrer-Policy "no-referrer" always;
+ add_header X-Content-Type-Options "nosniff" always;
+ add_header X-Download-Options "noopen" always;
+ add_header X-Frame-Options "SAMEORIGIN" always;
+ add_header X-Permitted-Cross-Domain-Policies "none" always;
+ add_header X-Robots-Tag "none" always;
+ add_header X-XSS-Protection "1; mode=block" always;
+
+ fastcgi_hide_header X-Powered-By;
+
+ index index.php index.html /nextcloud/index.php$request_uri;
+
+ location = /nextcloud {
+ if ( $http_user_agent ~ ^DavClnt ) {
+ return 302 /nextcloud/remote.php/webdav/$is_args$args;
+ }
+ }
+
+ location ~ ^/nextcloud/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { return 404; }
+ location ~ ^/nextcloud/(?:\.|autotest|occ|issue|indie|db_|console) { return 404; }
+
+ location ~ \.php(?:$|/) {
+ fastcgi_split_path_info ^(.+?\.php)(/.*)$;
+ set $path_info $fastcgi_path_info;
+
+ try_files $fastcgi_script_name =404;
+
+ include fastcgi_params;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+ fastcgi_param PATH_INFO $path_info;
+ fastcgi_param HTTPS on;
+
+ fastcgi_param modHeadersAvailable true;
+ fastcgi_param front_controller_active true;
+ fastcgi_pass php-handler;
+
+ fastcgi_intercept_errors on;
+ fastcgi_request_buffering off;
+ }
+
+ location ~ \.(?:css|js|svg|gif)$ {
+ try_files $uri /nextcloud/index.php$request_uri;
+ expires 6M;
+ access_log off;
+ }
+
+ location ~ \.woff2?$ {
+ try_files $uri /nextcloud/index.php$request_uri;
+ expires 7d;
+ access_log off;
+ }
+
+ location /nextcloud/remote {
+ return 301 /nextcloud/remote.php$request_uri;
+ }
+
+ location /nextcloud {
+ try_files $uri $uri/ /nextcloud/index.php$request_uri;
+ }
+ }
+}
+```
+
+Enable the site by running this command:
+
+```sh
+ln -s /etc/nginx/sites-available/nextcloud /etc/nginx/sites-enabled/
+```
+
+Next, we need to download the latest release tarball of Nextcloud. Go to
+https://nextcloud.com/install/#instructions-server and copy the URL of
+the .tar.bz2 tarball from the More Downloads dropdown menu then go to
+your server\'s shell prompt and download the tarball with wget. Here is
+an example:
+
+```sh
+wget https://download.nextcloud.com/server/releases/nextcloud-21.0.2.tar.bz2
+```
+
+Now we need to extract the Nextcloud tarball. Run the following command:
+
+```sh
+tar -xjf nextcloud*.tar.bz2 -C /var/www
+```
+
+If you have multiple Nextcloud tarballs in the current working directory
+you might want to manually specify which one you wish to extract.
+
+Let\'s correct the ownership and permissions of those files. Run the
+following commands:
+
+```sh
+chown -R www-data:www-data /var/www/nextcloud
+chmod -R 755 /var/www/nextcloud
+```
+
+
+Start and enable the php-fpm and the mariadb services (the name of the
+php-fpm service may have a version number ahead of it, use bash\'s tab
+autocomplete to help you out with that):
+
+```sh
+systemctl enable php7.4-fpm
+systemctl start php7.4-fpm
+systemctl enable mariadb
+systemctl start mariadb
+```
+
+Reload the nginx service:
+
+```sh
+systemctl reload nginx
+```
+
+Now we need to head to Nextcloud\'s web interface. Go to your web
+browser and go to your website, but go to the subdirectory \"nextcloud\"
+instead. Go to `https://example.org/nextcloud`. This will launch the
+configuration wizard.
+
+- Choose an admin username and secure password.
+- Leave Data folder at the default value unless it is incorrect.
+- For Database user, enter the user you set for the SQL database.
+- For Database password, enter the password you chose for the new user
+ in MariaDB.
+- For Database name, enter: `nextcloud`
+- Leave \"localhost\" as \"localhost\".
+- Click Finish.
+
+Congratulations, you have set up your own Nextcloud instance.
+
+## What\'s Next? {#whatsnext}
+
+Now you may be wondering: What do I do now? Here are some suggestions:
+
+- Rice your Nextcloud instance by changing your themeing and
+ installing new themes and plugins in Settings in the Nextcloud Web
+ Interface.
+- Install the Nextcloud Client on your personal computer and sync your
+ files to your instance.
+- Install the Nextcloud App on your mobile device and sync your files
+ to your instance.
+- Set up your email account on the Nextcloud Mail app on the web
+ interface to view and sync your email there (just like Gmail).
+- Schedule events with Nextcloud Calender.
+- Write notes in Markdown inside the Nextcloud Notes web and mobile
+ app.
+- Set the Nextcloud Dashboard as your web browser\'s homepage (it is
+ pretty nice).
+
+Enjoy your cloud services in freedom.
+
+------------------------------------------------------------------------
+
+*Written by [Matthew \"Madness\" Evan](https://github.com/MattMadness)*
diff --git a/content/nginx-tweaks.md b/content/nginx-tweaks.md
new file mode 100644
index 0000000..8e85af5
--- /dev/null
+++ b/content/nginx-tweaks.md
@@ -0,0 +1,45 @@
+---
+title: "Nginx Tweaks"
+date: 2022-06-16
+---
+
+The point of this article is to show you how to do some commonly-desired tweaks
+in Nginx while in the meantime helping you understand how it works.
+
+## Do not require `.html` in URLs
+
+If your website is using lots of `.html` files for pages, it\'s sort of
+overkill to make people type that in for every page they are looking for. We
+can remove that requirement with Nginx.
+
+Open your site\'s configuration file in `/etc/nginx/sites-enabled/` and within
+the `server` block, there should be a `location` block that looks something
+like this if you have followed [the guide here](/basic/nginx).
+
+```nginx
+location / {
+ try_files $uri $uri/ =404 ;
+}
+```
+
+What this means is that in the file location of `/`, i.e. anywhere and
+everywhere in the root file system, We will look for the three things listed in
+`try_files` in that order:
+
+1. `$uri`: a file that directly matches the content added after the domain.
+2. `$uri/`: a *directory* that directly matches the content added after the
+ domain.
+3. `=404`: if neither of those is found, we give a 404 error, which as you
+ probably know, signified \"Page not found.\"
+
+We will now change the content inside the `location` block to the below:
+
+```nginx
+location / {
+ if ($request_uri ~ ^/(.*)\.html$) { return 302 /$1; }
+ try_files $uri $uri.html $uri/ =404 ;
+}
+```
+
+`$1` here refers to the first content in the parentheses `()` in the preceeding
+regular expression.
diff --git a/content/openalias.md b/content/openalias.md
new file mode 100644
index 0000000..2760c0c
--- /dev/null
+++ b/content/openalias.md
@@ -0,0 +1,102 @@
+---
+title: "OpenAlias"
+date: 2021-07-01
+tags: ['server']
+---
+## The Problem
+
+Cryptocurrency can be unintuitive. After all, look at this annoying
+Monero address of ours:
+
+- `84RXmrsE7ffCe1ADprxLMHRpmyhZuWYScDR4YghE8pFRFSyLtiZFYwD6EPijVzD3aZiEpg57MfHEr1pGJNPXyJgENMnWrSh`
+
+It breaks up pages and looks ugly. When you copy and paste it to send
+money, you might be paranoid that you somehow added an extra character
+in there. That\'s all around a bad user experience.
+
+### It would be nice\...
+
+It would be nice if we could just input someone\'s email address or
+maybe a website and send Bitcoin or Monero to that instead. So instead
+of that long jumble, it would be easier to just type in someone\'s
+website or email and sending them money that way.
+
+## The Solution
+
+The [OpenAlias](https://openalias.org/) standards are just that. It uses
+[DNS](/basic/dns) settings, which you know something about, to link a
+website or an email address with a cryptocurrency address. It allows
+someone to simply put `landchad.net` or `chad@landchad.net` as a payment
+recipient and that will direct to that long address above.
+
+The default Monero wallet and Bitcoin\'s Electrum are already compatible
+with OpenAlias, as are a growing group of wallet software.
+
+## Let\'s do it.
+
+Open up your domain registar and open up your DNS settings for the
+website you would like to add.
+
+Open the **TXT record** section. Now, create an entry with text like
+that below:
+
+```txt
+oa1:xmr recipient_address=84RXmrsE7ffCe1ADprxLMHRpmyhZuWYScDR4YghE8pFRFSyLtiZFYwD6EPijVzD3aZiEpg57MfHEr1pGJNPXyJgENMnWrSh; recipient_name=LandChad.net;
+```
+
+Obviously change the address to your desired address and you may also
+give a proper name for yourself (this may be multiple words). Note that
+the entry above is **all one line**.
+
+Now create a new TXT entry and input this text into the **TXT Value**
+input box. Note here that I have create two entries:
+
+{{< img alt="openalias" src="/pix/openalias-01.png" link="/pix/openalias-01.png" >}}
+
+One entry\'s \"Host\" is left empty, this will allow people to send
+Monero by merely typing `landchad.net`.
+
+The second entry has \"chad\" as the \"Host\"; this will allow people to
+send money to `chad@landchad.net`, i.e. this is how you allow people to
+connect a Monero address with an email address.
+
+### Checking to see if it works\...
+
+Let\'s check to see if it works. In the Monero wallet, we can now type
+in `landchad.net` as a recipient:
+
+{{< img alt="checking" src="/pix/openalias-02.png" link="/pix/openalias-02.png" >}}
+
+And once we press the \"Resolve\" button, it automatically turns into
+that address we gave to the DNS!
+
+{{< img alt="It works!" src="/pix/openalias-03.png" link="/pix/openalias-03.png" >}}
+
+Now people can donate Monero to you without having to worry about QR
+codes or copying-and-pasting super-long public addresses!
+
+### Now with Bitcoin!
+
+OpenAlias was originally developed for Monero, but since it\'s such a
+good idea, Bitcoin wallets have implemented it as well, so let\'s add
+some TXT entries for Bitcoin. The OpenAlias TXT records have the same
+format, except for the **xmr** at the beginning is replaced with **btc**
+and obviously we use a Bitcoin address instead of Monero.
+
+```txt
+oa1:btc recipient_address=bc1q9f3tmkhnxj8gduytdktlcw8yrnx3g028nzzsc5; recipient_name=LandChad.net;
+```
+
+Add the TXT entries in and save:
+
+{{< img alt="bitcoin openalias entries" src="/pix/openalias-04.png" link="/pix/openalias-04.png" >}}
+
+And we can then check that it\'s working by trying to send money to
+`landchad.net` in Electrum. See that it automatically appends the
+address!
+
+{{< img alt="electrum resolves an openalias" src="/pix/openalias-05.png" link="/pix/openalias-05.png" >}}
+
+And that\'s it. Now users can easily send your website or email address
+Bitcoin or Monero without having to worry about hard to read addresses
+and QR codes.
diff --git a/content/page-quality.md b/content/page-quality.md
new file mode 100644
index 0000000..ba45488
--- /dev/null
+++ b/content/page-quality.md
@@ -0,0 +1,180 @@
+---
+title: "Page Quality"
+date: 2022-03-21
+tags: ['server']
+---
+After you\'ve deployed your website, you may want to consider improving
+its performance, accessibility, and search-engine optimization (SEO).
+Doing so can help make your website more user-friendly and increase its
+page rank in search results. Luckily, Google provides a [measurement
+tool](https://web.dev/measure) to help you improve these aspects. Start by
+entering your website\'s URL and click the *Run Audit* button (it will
+take 5-10 seconds to generate the report).
+
+Once the report has finished, you\'ll be greeted by a score for four
+different categories: *Performance*, *Accessibility*, *Best Practices*,
+and *SEO*. A lot of the tests listed are self-explanatory, and Google
+provides you with articles to help you pass them. Below are some easy
+ways to improve your scores, some specific to the nginx configuration
+used in the [landchad website tutorial.](/basic/nginx)
+
+## Performance
+
+### Serving static assets with an efficient cache policy
+
+Serving your files with an efficient cache policy will allow the user\'s
+browser to cache files such as pictures and CSS so that the browser doesn\'t
+need to fetch these files each time the page is visited.
+
+It\'s very easy to set this up in nginx. Just paste the following within the
+server block of your website\'s configuration file:
+
+```nginx
+# Media: images, icons, video, audio, HTC
+location ~* \.(?:jpg|jpeg|gif|png|ico|svg|webp)$ {
+ expires 1M;
+ access_log off;
+ # max-age must be in seconds
+ add_header Cache-Control "max-age=2629746, public";
+}
+
+# CSS and Javascript
+location ~* \.(?:css|js)$ {
+ expires 1y;
+ access_log off;
+ add_header Cache-Control "max-age=31556952, public";
+}
+```
+
+You can add more types of file extensions (mp3, mp4, ogg) as you see
+fit.
+
+If you\'re changing your CSS files a lot, caching could keep repeat
+users from getting the most up-to-date stylesheet. To combat this, you
+can version your stylesheets like so:
+
+```html
+<link rel="stylesheet" type="text/css" href="style.css?v=1.0.0">
+```
+
+Just increase the version number whenever you update your stylesheet,
+and the browser will re-update its cache.
+
+### Enable text compression
+
+Another easy addition to your websites configuration file. Enabling text
+compression is easy and will save bandwidth for users. Simply paste the
+following within the server block of your website\'s configuration file:
+
+```nginx
+gzip on;
+gzip_min_length 1100;
+gzip_buffers 4 32k;
+gzip_types text/plain application/x-javascript text/xml text/css;
+gzip_vary on;
+```
+
+After reloading nginx, you can test if compression is working by opening
+your browsers developer tools and going to the network tab. Refresh your
+website with the network tab, click on the item with your URL and look
+at the response headers. You should see `Content-Encoding: gzip` as one
+of the headers displayed.
+
+### Properly sizing images
+
+If you\'ve put images on your webpage, you\'ve most definitely gotten
+this warning. To pass this audit, you\'ll need to scale your images down
+using a tool like gimp or imagemagick to a size appropriate for your
+website. It doesn\'t make much sense to serve a high-res image for
+images that are rendered much smaller on a webpage.
+
+Once you\'ve scaled your image down, you can use a tool like `cwebp` to
+convert your images into the .webp format, a format specifically created
+for serving bandwidth concious images.
+
+First, you\'ll have to install the webp package:
+
+```sh
+apt install webp
+```
+
+Now you can easily convert your images to webp (keep in mind that it\'s
+much more effective to first size your images appropriately before
+this). Using the below command, you can specify the quality of the photo
+with the `q` option. I typically shoot for a quality in the range of
+60-80, depending on the image and how large it will be displayed on the
+webpage.
+
+```sh
+cwebp -q 80 your-photo.png -o your-photo.webp
+```
+
+You can now check the difference in size of the images using `ls`.
+
+```sh
+ls -lh your-photo*
+```
+
+After utilizing webp images, the audit typically goes away, but if you
+didn\'t scale your image properly before hand, it may still linger.
+
+## Accessibility
+
+### Image elements do not have \[alt\] attributes
+
+It may seem silly to add `alt` attributes to images, but it helps screen
+readers convey images to users and can help page rank as a result. The
+`alt` attribute should simply describe the image being displayed.
+
+```html
+<img src="img/cabin.webp" alt="A cabin nestled between pine trees">
+```
+
+## SEO
+
+### Document does not have a meta description
+
+Adding meta descriptions to your webpage allow for web-crawlers and bots
+to easily determine what content your website contains. Just like on
+other online platforms, you can give your webpage a long list of
+keywords to help increase the chance someone stumbles upon your site
+from a search engine. You don\'t need to add all of the below meta tags
+to pass the audit, only add what\'s necessary.
+
+```html
+// Instructions for web scrapers
+<meta name="robots" content="index, follow">
+
+<meta name="description" content="your website description>">
+<meta name="keywords" content="your, keywords, here">
+<meta name="author" content="your name>">
+
+// Facebook specific standard, but many websites use this so it has become almost standard to include
+<meta property="og:site_name" content="Site Name">
+<meta name="twitter:domain" property="twitter:domain" content="example.org">
+<meta name="og:title" property="og:title" content="Site Name">
+<meta property="og:description" content="your website description">
+<meta name="twitter:description" property="twitter:description" content="your website description">
+<meta name="og:image" content="https://link-to-an-image-that-represents-your-site">
+
+// below is for twitter sharing previews, you can test this at:
+// cards-dev.twitter.com
+<meta property="twitter:card" content="https://link-to-an-image-that-represents-your-site">
+<meta name="twitter:image:src" property="twitter:image:src" content="https://link-to-an-image-that-represents-your-site">
+<meta name="twitter:image" property="twitter:image" content="https://link-to-an-image-that-represents-your-site">
+<meta name="og:image:alt" property="og:image:alt" content="alt text for your image>">
+
+<meta property="og:url" content="example.org">
+<meta property="og:type" content="website">
+
+// If you have accounts on twitter or facebook that are relevant to your site
+<meta property="fb:admins" content="facebook group" >
+<meta name="twitter:site" property="twitter:site" content="@yourTwitterHandle">
+<meta name="twitter:creator" property="twitter:creator" content="@yourTwitterHandle>">
+```
+
+
+------------------------------------------------------------------------
+
+*Written by [Jacob.](https://mccor.xyz) Donate Monero
+[here.](https://mccor.xyz)*
diff --git a/content/peertube.md b/content/peertube.md
new file mode 100644
index 0000000..b0ec47e
--- /dev/null
+++ b/content/peertube.md
@@ -0,0 +1,284 @@
+---
+title: "PeerTube"
+date: 2021-07-31
+icon: 'peertube.svg'
+tags: ['service','activity-pub']
+short_desc: 'Your own self-hosted video-site also compatible with Activity Pub.'
+---
+
+PeerTube is a self-hosted and (optionally) federated video sharing
+platform that saves bandwith on videos the more people watch. PeerTube
+instances can follow each other to share videos and grow the federated
+network, but you can always keep your instance to yourself if you choose
+to.
+
+## Note on Bandwidth
+
+Video sharing is the most bandwidth intensive thing on the internet! If
+you plan on just having a small personal site with a few viewers and
+friends, that won\'t be a big concern, but most VPS providers like Vultr
+have caps on how much bandwidth can be used within a month without being
+throttled. This level is far beyond what most sites need, but it might
+be an issue with a video site!
+
+So if you plan on having a big video-sharing PeerTube site, it\'s a good
+idea to host it with a provider that offers infinite bandwidth. I
+strongly recommend getting a separate VPS with
+[Frantech/BuyVM](https://my.frantech.ca/aff.php?aff=3886). They have
+unmetered bandwidth, extremely cheap block storage for hosting many,
+many videos and they even have a good record of being censorship
+resistant.
+
+## Prerequisites
+
+**Most** of PeerTube\'s dependencies can be installed with this command:
+
+```sh
+apt install -y curl sudo unzip vim ffmpeg postgresql postgresql-contrib g++ make redis-server git python-dev cron wget
+```
+
+It\'s also important to start all associated daemons:
+
+```sh
+systemctl start postgresql redis
+```
+
+PeerTube also requires **NodeJS 14** and **yarn** which cannot be
+installed from the Debian repositories. This means they have to be
+installed from separate, external repos:
+
+```sh
+curl -fsSL https://deb.nodesource.com/setup_14.x | bash -
+apt install -y nodejs
+npm install --global yarn
+```
+
+Now we create a PeerTube user to run and handle PeerTube with the proper
+permissions:
+
+```sh
+useradd -m -d /var/www/peertube -s /bin/bash -p peertube peertube
+```
+
+## Database
+
+PeerTube requires a PostgreSQL database to function. To create it, first
+make a new Postgres user named PeerTube:
+
+```bash
+su -l postgres
+createuser -P peertube
+createdb -O peertube -E UTF8 -T template0 peertube_prod
+psql -c "CREATE EXTENSION pg_trgm;" peertube_prod
+psql -c "CREATE EXTENSION unaccent;" peertube_prod
+exit
+```
+
+Be sure to **make note of your Postgres user password,** as it will be
+needed later when setting up PeerTube.
+
+## Installation
+
+Using `su -l`, we will become the PeerTube user to create the required
+directories and download and install PeerTube itself with the proper
+permissions. First, we create the required directories.
+
+```sh
+su -l peertube
+mkdir config storage versions
+chmod 750 config
+```
+
+### Downloading PeerTube
+
+Still as the PeerTube user, we can now check for the most recent
+PeerTube versions number, download and install it in the newly created
+`versiond` directory.
+
+```bash
+VERSION=$(curl -s https://api.github.com/repos/chocobozzz/peertube/releases/latest | grep tag_name | cut -d '"' -f 4)
+cd /var/www/peertube/versions
+wget "https://github.com/Chocobozzz/PeerTube/releases/download/${VERSION}/peertube-${VERSION}.zip"
+unzip peertube-${VERSION}.zip
+rm peertube-${VERSION}.zip
+```
+
+### Installation via Yarn
+
+The downloaded release can then be symbolically linked to
+`/var/www/peertube/peertube-latest` and **yarn** is used to install
+PeerTube:
+
+```sh
+cd /var/www/peertube
+ln -s versions/peertube-${VERSION} ./peertube-latest
+cd ./peertube-latest
+yarn install --production --pure-lockfile
+```
+
+## Configuration
+
+PeerTube\'s default config file can be copied over to
+`/var/www/peertube/config/production.yaml` so it can actually be used:
+
+Note that we are still running these as the PeerTube user (having run
+`su -l peertube`).
+
+```sh
+cd /var/www/peertube
+cp peertube-latest/config/production.yaml.example config/production.yaml
+```
+
+Now the `production.yaml` file must be edited in the following ways:
+
+First, add the hostname:
+
+```yaml
+webserver:
+ https: true
+ hostname: 'example.org'
+ port: 443
+```
+
+Then, the database:
+
+```yaml
+database:
+ hostname: 'localhost'
+ port: 5432
+ ssl: false
+ suffix: '_prod'
+ username: 'peertube'
+ password: 'your_password'
+ pool:
+ max: 5
+```
+
+An email to generate the admin user:
+
+```yaml
+admin:
+ # Used to generate the root user at first startup
+ # And to receive emails from the contact form
+ email: 'chad@example.org'
+```
+
+And **optionally,** email server information:
+
+```yaml
+smtp:
+ # smtp or sendmail
+ transport: smtp
+ # Path to sendmail command. Required if you use sendmail transport
+ sendmail: null
+ hostname: mail.example.org
+ port: 465 # If you use StartTLS: 587
+ username: your_email_username
+ password: your_email_password
+ tls: true # If you use StartTLS: false
+ disable_starttls: false
+ ca_file: null # Used for self signed certificates
+ from_address: 'admin@example.org'
+```
+
+At this point, we have done all we need to do as the PeerTube user. Run
+`exit` or press `Ctrl-d` to log out and return to the root prompt where
+we will configure Nginx and other system settings.
+
+## Certbot
+
+First, we will want a Certbot SSL certificate to encrypt connections to
+our PeerTube instance. Just run the following:
+
+```sh
+certbot --nginx -d peertube.example.org certonly
+```
+
+## Nginx
+
+PeerTube includes an Nginx configuration that can be copied over to
+`/etc/nginx/sites-available:`
+
+```sh
+cp /var/www/peertube/peertube-latest/support/nginx/peertube /etc/nginx/sites-available/peertube
+```
+
+Because the PeerTube config is so long, it\'s recommended to use `sed`
+to modify the contents of the file, replacing `${WEBSERVER_HOST}` with
+your hostname, and `$(PEERTUBE_HOST)` with your localhost and port,
+which by default should be `127.0.0.1:9000`:
+
+```sh
+sed -i 's/${WEBSERVER_HOST}/example.org/g' /etc/nginx/sites-available/peertube
+sed -i 's/${PEERTUBE_HOST}/127.0.0.1:9000/g' /etc/nginx/sites-available/peertube
+```
+
+Once you\'re happy with the Nginx config file, link it to
+`sites-enabled` to activate it:
+
+```sh
+ln -s /etc/nginx/sites-available/peertube /etc/nginx/sites-enabled/peertube
+```
+
+## Running PeerTube
+
+A config file for a systemd daemon is included in PeerTube and can be
+setup and started like so:
+
+```sh
+cp /var/www/peertube/peertube-latest/support/systemd/peertube.service /etc/systemd/system/
+systemctl daemon-reload
+systemctl start peertube
+```
+
+PeerTube will take a minute or so to start, but after it does, you can check
+its status with `systemctl status peertube` and at this point, your
+PeerTube site should be live!
+
+## Using PeerTube
+
+To set a password for your admin user, run:
+
+```sh
+cd /var/www/peertube/peertube-latest
+NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run reset-password -- -u root
+```
+
+Login to your PeerTube instance using the admin email specified in your
+`production.yaml` file and the admin password you just set.
+
+{{< img alt="PeerTube login" src="/pix/peertube-login.jpg" >}}
+
+Once logged in, it\'s recommended to create a separate user without
+admin privileges for uploading videos to PeerTube. This can be done
+easily from the users tab in the administration section.
+
+Enjoy your PeerTube instance!
+
+------------------------------------------------------------------------
+
+## Updating PeerTube
+
+PeerTube is constantly adding new features, so it\'s a good idea to
+[check for new
+updates](https://github.com/Chocobozzz/PeerTube/blob/develop/CHANGELOG.md)
+and add them if you wish. Just in the past year, they have added
+livestreaming and more.
+
+Updating is fairly easy now since an `upgrade.sh` script has been added.
+Just run:
+
+```sh
+cd /var/www/peertube/peertube-latest/scripts && sudo -H -u peertube ./upgrade.sh
+```
+
+Although check the
+[changelog](https://github.com/Chocobozzz/PeerTube/blob/develop/CHANGELOG.md)
+to see if there are additional manual requirements for particular
+updates.
+
+------------------------------------------------------------------------
+
+*Written by [Denshi.](https://denshi.org) Donate Monero
+[here](https://denshi.org/donate.html)
+[\[QR\]](https://denshi.org/images/monero.jpg)*
diff --git a/content/pleroma.md b/content/pleroma.md
new file mode 100644
index 0000000..78aab03
--- /dev/null
+++ b/content/pleroma.md
@@ -0,0 +1,186 @@
+---
+title: "Pleroma"
+date: 2021-07-01
+icon: 'pleroma.svg'
+tags: ['service','activity-pub']
+short_desc: 'A federated Twitter-like microblogging system.'
+---
+Hopefully by now you won\'t have to be sold on the invasive practices
+that social media companies conduct. Websites such as Facebook and
+Twitter aquire so much data on users that they often know more about you
+than you know about yourself. The simple solution to this is to not use
+social media. However, that just isn\'t an option for most people. So
+the next best thing is to setup a self-hosted and federalised social
+media site so that you have full control over your data. I\'ve
+previously made [a video showing all the steps in depth if you want to
+check it out.](https://www.youtube.com/watch?v=l7mVsLSsotU) If you run
+into any issues I suggest you look at the video.
+
+You\'ll need a server or VPS. Nearly any Operating system is supported
+but for this tutorial I\'m gonna presume you\'re using a Debian-based
+OS. You\'ll also need a domain name pointing to your server\'s IP
+address [which is explained in this tutorial.](/basic/dns)
+
+## Installation
+
+### Setting Up and Configuring
+
+First things first you\'ll need to make sure that you\'ve hardened you
+SSH so that password authentication is disabled and you\'ll also want to
+setup Fail2Ban. There\'s a great tutorial on how to do this [which can
+be read here.](/sshkeys)
+
+Next we\'ll install the required packages:
+
+```sh
+apt install -y curl unzip libncurses5 postgresql postgresql-contrib nginx certbot libmagic-dev
+```
+
+You can manually configure postgreSQL to suit your system better. [Check
+out the documentation
+here](https://docs-develop.pleroma.social/backend/configuration/postgresql/)
+and then run the below command:
+
+```sh
+systemctl restart postgresql
+```
+
+### Installing the Pleroma App
+
+#### First as the root user
+
+Pleroma is not in the Debian app repositories, so we will install it
+manually. First create the Pleroma user by running the below command:
+
+```sh
+useradd -m -s /bin/bash -d /opt/pleroma pleroma
+```
+
+Then, still as root, we will create the required directories and give
+the Pleroma user ownership of them.
+
+```sh
+mkdir -p /var/lib/pleroma/uploads
+chown -R pleroma /var/lib/pleroma
+mkdir -p /var/lib/pleroma/static
+chown -R pleroma /var/lib/pleroma
+mkdir -p /etc/pleroma
+chown -R pleroma /etc/pleroma
+```
+
+#### Now, as the new Pleroma user
+
+Now run `su -l pleroma` to login as the Pleroma user. Now use the `curl`
+command below to download the Pleroma software and unzip it.
+
+```sh
+curl 'https://git.pleroma.social/api/v4/projects/2/jobs/artifacts/stable/download?job=amd64' -o /tmp/pleroma.zip
+unzip /tmp/pleroma.zip -d /tmp/
+```
+
+Note that we are downloading the **amd64** version here. If you know you
+have a different CPU architecture, replace that with whatever your
+architecture is.
+
+```sh
+mv /tmp/release/* /opt/pleroma
+rmdir /tmp/release
+rm /tmp/pleroma.zip
+./bin/pleroma_ctl instance gen --output /etc/pleroma/config.exs --output-psql /tmp/setup_db.psql
+```
+
+We need to briefly return to the root user so we can run the following
+command (via the postgres user) to set up the database. Type `ctrl-d` or
+run `exit` to return to the root user, then run:
+
+```sh
+su postgres -s $SHELL -lc "psql -f /tmp/setup_db.psql"
+```
+
+Then return to the pleroma user with `su -l pleroma` and we will test to
+see that Pleroma can run:
+
+```sh
+./bin/pleroma_ctl migrate
+./bin/pleroma daemon
+```
+
+That will initialize Pleroma. It might take as long as a minute to get
+started, so wait a bit, then run the following:
+
+```sh
+curl http://localhost:4000/api/v1/instance
+```
+
+If everything is working, this command will give you a long line of
+messy output. If it is not, you will get a connection error message.
+Once it is working successfully, stop the Pleroma daemon and we will
+interface Pleroma with the web server.
+
+```sh
+./bin/pleroma stop
+```
+
+### Setup and Configure Nginx
+
+Return again to the root user. Let\'s copy Pleroma\'s Nginx
+configuration file from the template given in the installation and
+enable it:
+
+```sh
+cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/sites-available/pleroma.conf
+ln -s /etc/nginx/sites-available/pleroma.conf /etc/nginx/sites-enabled/pleroma.conf
+```
+
+Edit the `etc/nginx/sites-available/pleroma.conf` file and replace
+**example.tld** with your domain name.
+
+We now have to get a SSL certificate to enable encryption, since we have
+a model configuration that already includes SSL information, just check
+the brief [the standalone certificate page](/standalone) to get the
+needed certificate. Once you\'ve got your cert setup, copy over the
+Nginx configuration with the below command:
+
+Once everything, including your Cerbot certificate is ready, simply
+reload Nginx with this command:
+
+```sh
+systemctl reload nginx
+```
+
+### Setting up the service
+
+Pleroma itself runs on a SystemD service similar to other things running
+on your server like Nginx. To start the service up run the below
+commands:
+
+```sh
+cp /opt/pleroma/installation/pleroma.service /etc/systemd/system/pleroma.service
+systemctl start pleroma
+systemctl enable pleroma
+```
+
+If everything worked then when you go to your domain in the web browser
+you should see a bare-bones Pleroma instance.
+
+### Creating an Admin User
+
+You\'ll be able to create new accounts on the Pleroma instance in the
+login section on the website but the easiest way to setup an admin
+account is with the CLI. Simply run the below command replaced with your
+username:
+
+```sh
+su -l pleroma
+./bin/pleroma_ctl user new username username@example.org --admin
+```
+
+If you run into any issues then [feel free to checkout the
+documentation](https://docs-develop.pleroma.social/backend/installation/otp_en/)
+or send me an email or message. My details are below.
+
+- [biasedriot.co](https://biasedriot.co)
+- [youtube](https://www.youtube.com/channel/UCehh50T6qtDpt_kEUF33GJw)
+- Bitcoin: `1Dmn9jEtWAhdLk1HHWkUVNeDdAaBCwNajm`{.crypto}
+- Monero:
+ `84Y4FZiTbLeR5qc1fBrBhB1yq5agKtEdoixq2w1ysXJv486MiBCz3czGT15bqeXDPpdLoNyF93inxY3BCk6g8mrDMNKoArS`
diff --git a/content/prosody.md b/content/prosody.md
new file mode 100644
index 0000000..c32dfe1
--- /dev/null
+++ b/content/prosody.md
@@ -0,0 +1,272 @@
+---
+title: "Prosody"
+date: 2022-04-03
+icon: 'prosody.svg'
+tags: ['service']
+short_desc: 'A minimalist XMPP chat server.'
+---
+
+XMPP is a fantastically simple protocol that\'s usually used as a messenger.
+It\'s highly extensible, better than IRC, lighter and more decentralized than
+Matrix, and normie social media like Telegram can\'t hold a candle to it.
+
+XMPP is so decentralized and extensible that there are many *different*
+XMPP servers. Here, let\'s set up an [Prosody](https://prosody.im/) XMPP
+server.
+
+## Installation
+
+Prosody is in the Debian repositories, so we can easily install it on
+our server with the following command:
+
+```sh
+apt install prosody
+```
+
+## Configuration
+
+The Prosody configuration file is in `/etc/prosody/prosody.cfg.lua`. To
+set it all up, we will be changing several things.
+
+### Setting Admins
+
+Let\'s go ahead and set who our admin(s) will be. Find the line that
+says `admins = { }` and to this we can specify one or more server
+admins.
+
+```cfg
+# To add one admin:
+admins = { "chad@example.org" }
+
+# We can add more than one by separating them by commas. (This file is written in Lua.)
+admins = { "chad@example.org", "chadmin@example.org" }
+```
+
+Note that we have not created these accounts yet, we will do this
+[below](#user).
+
+### Set the Server URL
+
+Find the line `VirtualHost "localhost"` and replace `localhost` with
+your domain. In our case, we will have `VirtualHost "example.org"`
+
+### Multi-User Chats
+
+Most people will probably want the ability to have chats with more than
+two users. This is easily enough to enable. In the config file, add the
+following:
+
+```cfg
+Component "chat.example.org" "muc"
+ modules_enabled = { "muc_mam" }
+ restrict_room_creation = "admin"
+```
+
+On the first line, you must have a separate subdomain for your
+multi-user chats. I use the `chat.` subdomain, but some use `muc.`.
+Anything if possible.
+
+The second line is important because it prevents non-admins from
+creating and squatting rooms on your server. The only situation where
+you might not want that is if you indend to open a general public chat
+system for people you don\'t know.
+
+Read more about the `muc` plugin on the Prosody documentation page
+[here](https://prosody.im/doc/modules/mod_muc).
+
+### Enabling chat histories
+
+By default, Prosody will send out messages received only to the first
+available clients. That means that if you have your desktop client
+turned off and your cell phone receives a message, it will *not* be
+available to the desktop client when you start it.
+
+While this may be preferred in some cases, enable the MAM module
+(Message Archive Management) to have the server hold on messages and
+sync them to all clients.
+
+Within the `modules_enabled` block, you can uncomment the `mam` line to
+enable it. You can see other settings for this module
+[here](https://prosody.im/doc/modules/mod_mam) like, for example, how
+long a server should hold on to message histories for synching.
+
+Note also that Prosody comes with the `carbons` activated module by
+default, which is related. This will send received messages to *all*
+active clients (your phone and desktop), although it will not save
+messages like MAM for clients not online or to be added later.
+
+### File sharing
+
+With this we can bring XMPP to the level of other popular instant
+messaging applications like Matrix and whatsapp. It is extremely easy to
+setup. This part is optional, but it can make XMPP more normie-friendly
+if you plan on moving family members and friends over to XMPP.
+
+First we need to install extra prosody modules. Run the following
+command:
+
+```sh
+apt install prosody-modules
+```
+
+Then we can add the following line to you prosody config file to enable
+file uploads:
+
+```cfg
+Component "uploads.example.org" "http_upload"
+```
+
+As you will notice, you need another subdomain for this. We will add an
+ssl certficate for this later.
+
+You will also need to go back to `modules_enabled` and uncomment the
+`http_files` module. This is used to actually serve the files to users.
+
+And the last part of the setup is to enable the built in proxy server.
+This helps with file transfers for devices behind a NAT, and unless you
+are using XMPP in a LAN, you probably need this. Enable the proxy by
+adding the following line to the config:
+
+```cfg
+Component "proxy.example.org" "proxy65"
+```
+
+As you can see, another subdomain is needed. We will add ssl
+certificates for this later.
+
+At this point, file sharing is now setup and ready to be used. Although
+there are some concerns that should be addressed.
+
+A big concern with file sharing is large files, seeing as all files
+shared over XMPP will be stored on your server. This can become a
+problem when many (and large) files are being shared. We can put a cap
+on large files by adding the following line to our config:
+
+```cfg
+http_upload_file_size_limit = 20971520
+```
+
+This puts a 20MB cap on all files being shared. The value is specified
+in bytes. You can also specify after how long files should be deleted by
+adding the following line:
+
+```cfg
+http_upload_expire_after = 60 * 60 * 24 * 7
+```
+
+The value is specified in seconds. The above line will make prosody
+delete files after a week.
+
+If it is for some reason neccessary, you can also manually invoke expiry
+with the following command:
+
+```cfg
+prosodyctl mod_http_upload expire
+```
+
+### Other things to check
+
+Check the config file for other settings you might want to change. For
+example, if you want to run a general public XMPP server, you can allow
+anyone to create an account by changing `allow_registration` to `true`.
+
+Another thing you can do is enable the `csi_simple` module, which will
+add some optimizations for mobile devices.
+
+Another thing worth noting is the `archive_expires_after = "1w"` line.
+This specifies after how long message archives will be deleted.
+
+Also the `smacks` module helps a lot with slow internet connections.
+
+## Certificates
+
+Obviously, we want to have client-to-server and server-to-server
+encryption. Nowadays, use can use Certbot to generate certificates and
+use a convenient command below `prosodyctl` to import them.
+
+**If you have multi-user chat enabled, be sure to get a certificate for
+that subdomain as well.** Include the `--nginx` option assuming you have
+an Nginx server running.
+
+```sh
+certbot -d chat.example.org --nginx
+```
+
+**If you have file sharing enabled, be sure to get a certificate for
+those subdomains as well.**
+
+```sh
+certbot -d uploads.example.org --nginx
+certbot -d proxy.example.org --nginx
+```
+
+Once you have the certificates for encryption, run the following to
+import them into Prosody.
+
+```sh
+prosodyctl --root cert import /etc/letsencrypt/live/
+```
+
+Note that you might get an error that a certificate has not been found
+if your `muc` subdomain and your main domain share a certificate. It
+should still work, this is just notifying you that no specific
+certificate for the subdomain.
+
+**Note:** The above command will need to be rerun when certificates are
+renewed. You may want to create a [cronjob](/cron) to have this done
+automatically.
+
+## Creating users/admins manually {#user}
+
+Let\'s manually create the admin user we prepared for above. Note that
+you can indeed do this in your XMPP client if you have not disabled
+registration, but this is how it is done on the command line:
+
+```sh
+prosodyctl adduser chad@example.org
+```
+
+This will prompt you to create a password as well.
+
+## Make changes active
+
+With any system service, use `systemctl reload` or `systemctl restart`
+to make the new settings active:
+
+```sh
+systemctl restart prosody
+```
+
+## Using your Server!
+
+Once your server is set up, you just need an XMPP client to use your new
+and secure chat system.
+
+- GNU/Linux: [Dino](https://dino.im/) or [Gajim](https://gajim.org/)
+- Windows: [Gajim](https://gajim.org/) also runs on Windows.
+- Android: [Conversations.im](https://conversations.im/) or
+ [snikket](https://snikket.org/)
+- Mac/iOS: [Monal IM](https://monal.im/) or
+ [Siskin](https://siskin.im/) for iOS alone
+- command-line (GNU/Linux, MacOS, Windows):
+ [Profanity](https://profanity-im.github.io/)
+- [See a more complete list kept by
+ XMPP](https://xmpp.org/software/clients.html)
+
+Install whichever of these clients you want on your computer or phone
+and you can log into your new XMPP server with the account you made.
+Note that if you enabled public registration, anyone can create an
+account on your server through one of these clients.
+
+### Account addresses
+
+XMPP account addressed look just like email addresses:
+`username@example.org`. You can message any account on any XMPP server
+on the internet with that format.
+
+### Note on MUCs (multi-user chats)
+
+Remember that MUCs are kept on a separate subdomain that we created and
+should\'ve gotten a certificate for above, for example,
+`chat.example.org`. Chatrooms are created and referred to in the
+following format: `#chatroomname@chat.example.org`.
diff --git a/content/radicale.md b/content/radicale.md
new file mode 100644
index 0000000..b24f8ef
--- /dev/null
+++ b/content/radicale.md
@@ -0,0 +1,105 @@
+---
+title: "Radicale"
+date: 2021-10-07
+pix: 'radicale.svg'
+icon: 'radicale.svg'
+tags: ['service']
+short_desc: 'A private calendar, contact and to-do list system.'
+---
+
+Radicale is an open source calDAV server. CalDAV is a widely supported
+internet standard for calendars, todo-lists and contacts. Hosting your
+own calDAV server allows sharing calendars between mutliple devices.
+
+More information can be found on the projects offical website:
+[radicale.org](https://radicale.org/3.0.html).
+
+## Installing Radicale
+
+Firstly, we have to install radicale on our system, luckily for us
+radicale is packaged for the most used distros.
+
+```sh
+apt install radicale apache2-utils
+```
+
+Next we need to configure Radicale. We configure radicale to be
+accessible from other machines, how Radicale handles users and where the
+files should be stored. Open /etc/radicale/config with your favourite
+editor and add this configuration.
+
+```systemd
+[server]
+# Bind all addresses
+hosts = 0.0.0.0:5232, [::]:5232
+
+[auth]
+type = htpasswd
+htpasswd_filename = /etc/radicale/users
+htpasswd_encryption = bcrypt
+
+[storage]
+filesystem_folder = /var/lib/radicale/collections
+```
+
+As you can see under \[auth\] we use htpasswd to manage the users.
+Execute the following command to add a new user to Radicale.
+
+```sh
+htpasswd -B -c /etc/radicale/users username
+```
+
+As Radicale stands now it is fully functional and after starting it by
+executing its binary, can be accessed under example.org:5232. But there
+are two additional things we can do to make using and managing Radicale
+way easier.
+
+### Setting up a Nginx reverse proxy
+
+Because the URL of your Radicale server is an URL you will have to
+remember and enter it on any device you want to use your calendar on it
+is advised to set up a reverse proxy.
+
+```nginx
+server {
+ listen 443 ssl;
+ listen [::]:443 ssl;
+ server_name cal.example.org;
+ location / {
+ proxy_pass http://localhost:5232/; # The / is important!
+ }
+ # You can also leave these two lines out and use certbot
+ ssl_certificate /etc/ssl/nginx/cal.example.com/fullchain.pem;
+ ssl_certificate_key /etc/ssl/nginx/cal.example.com/privkey.pem;
+}
+```
+
+### Run as a service
+
+Running Radicale as a service makes managing it much easier. Add this
+config to /etc/systemd/system/radicale.service.
+
+```systemd
+[Unit]
+Description=A simple CalDAV (calendar) and CardDAV (contact) server
+
+[Service]
+ExecStart=/usr/bin/env python3 -m radicale
+Restart=on-failure
+
+[Install]
+WantedBy=default.target
+```
+
+After creating the config load, start and enable the service with the
+following commands.
+
+```sh
+systemctl daemon-reload
+systemctl enable --now radicale
+```
+
+## Contribution
+
+Author: Jocomol -- [jocomol.ch](https://jocomol.ch) \-- XMR:
+`41kLv68Nk4N3zvTRFYtHZfRRFMgXkxK2FcXDeCSa4yNwBGTBa1WQ8HtXL8cCAcoZ2iSLBCS6HQqdpRSf56ecMBgWTkn2ARt`{.crypto}
diff --git a/content/rss-bridge.md b/content/rss-bridge.md
new file mode 100644
index 0000000..5876d88
--- /dev/null
+++ b/content/rss-bridge.md
@@ -0,0 +1,114 @@
+---
+title: "RSS Bridge"
+date: 2021-07-05
+tags: ['service']
+icon: 'rss.svg'
+short_desc: 'Creates RSS feeds for normie sites like Facebook.'
+---
+RSS Bridge is a useful utility you can use to help you avoid the big
+tech sites, like Facebook and Twitter, which instead of the feed you
+usually would see, will be a based and minimalist RSS feed.
+
+You\'ll need a server or VPS. Nearly any Operating system is supported
+but for this tutorial I\'m gonna presume you\'re using a Debian-based
+OS. You\'ll also need a domain name pointing to your server\'s IP
+address [which is explained in this tutorial.](/basic/dns)
+
+## Installation
+
+### Setting Up and Configuring
+
+First things first you\'ll need to make sure that you\'ve hardened you
+SSH so that password authentication is disabled and you\'ll also want to
+setup Fail2Ban. There\'s a great tutorial on how to do this [which can be read here.](/sshkeys)
+
+Next we\'ll install the required packages:
+
+```sh
+apt install -y curl unzip nginx certbot php-fpm php-mysql php-cli php7.4-mbstring php7.4-curl php7.4-xml php7.4-sqlite3 php7.4-json
+```
+
+We now have to create the website configuration file. Create/open the a
+file below:
+
+```sh
+nano /etc/nginx/sites-available/rss-bridge
+```
+
+And add the following content:
+
+```nginx
+server {
+ root /var/www/rss-bridge;
+ index index.php index.html index.htm index.nginx-debian.html;
+ server_name rss-bridge.example.org;
+
+ location / {
+ try_files $uri $uri/ =404;
+ }
+
+ location ~ \.php$ {
+ include snippets/fastcgi-php.conf;
+ fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
+ }
+
+ location ~ /\.ht {
+ deny all;
+ }
+}
+```
+
+After you have saved the file, you need to create a symlink so the
+server actually will read the file.
+
+```sh
+ln -s /etc/nginx/sites-available/rss-bridge /etc/nginx/sites-enabled/rss-bridge
+```
+
+Then we have to create the folder where the service will reside in.
+
+```sh
+mkdir -p /var/www/rss-bridge
+cd /var/www/rss-bridge
+```
+
+Lets download the latest version of RSS-Bridge in the directory.
+
+The newest version can be found
+[here](https://github.com/RSS-Bridge/rss-bridge/releases), at the time of
+writing that is \"RSS-Bridge 2021-04-25.\"
+
+```sh
+wget https://github.com/RSS-Bridge/rss-bridge/archive/refs/tags/2021-04-25.zip
+```
+
+Unzip the file:
+
+```sh
+unzip 2021-04-25.zip
+```
+
+This will create a directory called rss-bridge-version-number, we now
+want to move all the file contents of the newly created directory to the
+one we are in
+
+```sh
+mv rss-bridge-2021-04-25/* .
+rm -rf rss-bridge-2021-04-25 2021-04-25.zip
+```
+
+Now all we need to do is grant read/write permissions and reload the web
+server.
+
+```sh
+chown -R www-data:www-data /var/www/rss-bridge
+systemctl reload nginx
+```
+
+That\'s it, you should now have a working rss-bridge installed. But you
+should definately get an SSL certifcate installed [which is done briefly here](/basic/certbot).
+
+- [handskemager.xyz](https://handskemager.xyz)
+- Bitcoin: `bc1qhfjgwjzksf2auqjefwpvq20wvyugq3lhqgkxvu`{.crypto}
+- Monero:
+ `88cPx6Gzv5RWRRJLstUt6hACF1BRKPp1RMka1ukyu2iuHT7iqzkNfMogYq3YdDAC8AAYRqmqQMkCgBXiwdD5Dvqw3LsPGLU`{.crypto}
diff --git a/content/rss-feed.md b/content/rss-feed.md
new file mode 100644
index 0000000..ec91488
--- /dev/null
+++ b/content/rss-feed.md
@@ -0,0 +1,95 @@
+---
+title: "Creating an RSS Feed"
+tags: ['concepts']
+date: 2022-07-02
+draft: true
+---
+
+RSS feeds are an easy way to be notified about new content from various
+websites, and they are easy to implement in your website.
+
+## How an RSS Feed Works
+
+Some websites with frequently changing content like blogs, podcasts, or
+video sharing sites, will have a link to a file containing the RSS feed
+and its items.
+
+When there is new content, a new item can be added to the RSS feed, and
+old items can optionally be removed from the RSS feed. A user\'s feed
+reader can check an RSS feed for new items and notify the user about
+them or organize them.
+
+## Writing an RSS Feed
+
+RSS feeds are written as XML (e**x**tensible **m**arkup **l**anguage)
+files, so they can be written and served similar to HTML webpages.
+
+We will start by creating a file for our RSS feed. Make sure the file
+name ends with `.rss` or `.xml`. Then, write the following code in the
+file:
+
+```xml
+<?xml version="1.0" encoding="UTF-8" ?>
+<rss version="2.0">
+ <channel>
+ </channel>
+</rss>
+```
+
+The `<rss>` tag specifies that there is an RSS feed in between the
+`<rss>` and `</rss>` tags. `version="2.0"` specifies that version 2.0 of
+RSS is used. The items in an RSS feed go in between the `<channel>` and
+`</channel>` tags.
+
+### Title, Description, and Link
+
+Now we will write a title and description for our RSS feed, as well as a
+link to the webpage that the RSS feed goes with. In this example, we
+will be writing an RSS feed for a blog called **LandChad\'s Blog**.
+
+In between the `<channel>` and `</channel>` tags, the `<title>` tag will
+be used to label the feed as **LandChad\'s Blog**. The `<description>`
+and `<link>` tags are used for the description of the feed and a link to
+the corresponding webpage.
+
+ ```xml
+ <channel>
+ <title>LandChad's Blog</title>
+ <description>LandChad's writings and ideas</description>
+ <link>https://example.org/blog</link>
+ </channel>
+ ```
+
+{{< img src="/pix/rss-01.png" alt="LandChad's blog feed" link="/pix/rss-01.png" >}}
+
+### Feed Items
+
+Now we will add items to the RSS feed. These items are listed in the
+user\'s feed reader and can represent different content on a page such
+as blog posts or videos. In this example, there is a blog post called
+**RSS is Amazing!**.
+
+The `<item>` tag is used to add items to the RSS feed. An item is given
+a title using the `<title>` tag to label the item. The item will have a
+link to its webpage using the `<link>` tag and an item description using
+the `<description>` tag.
+
+The date and time of an item can be specified using the `<pubDate>` tag.
+The date and time **must follow a specific format**. In the example
+below, the item was posted on **Friday, October 1, 2021 at 2:27 PM in
+the -0400 time zone**.
+
+```xml
+<item>
+ <title>RSS is Amazing!</title>
+ <link>https://example.org/blog/2021-10-1-rss</link>
+ <description>RSS is a good notification system.</description>
+ <pubDate>Fri, 1 Oct 2021 14:27:00 -0400</pubDate>
+ </item>
+ ```
+
+{{< img src="/pix/rss-02.png" alt="LandChad's Blog feed with an item" link="/pix/rss-02.png" >}}
+
+## Contributor
+
+[ClosedGL](https://closedgl.xyz)
diff --git a/content/rsync.md b/content/rsync.md
new file mode 100644
index 0000000..b2ccc07
--- /dev/null
+++ b/content/rsync.md
@@ -0,0 +1,104 @@
+---
+title: "Rsync: Upload and Sync Files and Websites"
+date: 2021-07-01
+img: 'rsync.png'
+tags: ['server']
+---
+
+rsync is a simple way to copy files and folders between your local computer and
+server. While you can install [Nextcloud](/nextcloud) is a more normie-friendly
+Dropbox/Google Drive-like way to share files, people familiar with the
+command-line will find all they need in the simple `rsync` command.
+
+It not only makes file-transfer easy, but it allows you to build and
+maintain your website offline, then easily upload it to the proper
+directory on your server so you don\'t need to constantly be logged into
+your server to modify your site.
+
+## Installing rsync
+
+Run the following on your server *and* on your local machine.
+
+```sh
+apt install rsync
+```
+
+## Uploading files with rsync
+
+From your local machine you can upload files to your server like this:
+
+```sh
+rsync -rtvzP /path/to/file root@example.org:/path/on/the/server
+```
+
+You will be prompted for the root password and then uploading will
+commence.
+
+If you omit **root@**, rsync will not attempt to log in as root, but
+whatever your local username is.
+
+### Options to rsync
+
+In this command, we give several options to rsync. You can remove some of these
+or add to them based on your needs:
+
+- `-r` -- run recurssively (include directories)
+- `-t` -- transfer modification times, which allows skipping files
+ that have not been modified on future uploads
+- `-v` -- visual, show files uploaded
+- `-z` -- compress files for upload
+- `-P` -- if uploading a large file and upload breaks, pick up where
+ we left off rather than reuploading the entire file
+
+Avoid using the commonly used `-a` option when uploading to a server. It can
+transfer your local machine\'s user and group permissions to your
+server, which might cause breakage.
+
+But `-a` is useful for making back-ups of important directories. It's an alias for many options at once (`-rlptgoD`)---read `man rsync` for the details.
+
+### Scriptability
+
+It\'s a good idea to build your website offline, then make an rsync
+script or bash alias like the one above to upload the edited files when
+you have made updates.
+
+### Password-less authentication
+
+To avoid having to manually input your password each upload, you can set
+up [SSH keys](/sshkeys) to securely idenitify yourself and computer
+as a trusted.
+
+### Picky trailing slashes
+
+rsync is very particular about trailing slashes. This is useful, but can
+be confusing to some new users. Suppose we run the following wanting to
+mirror our offline copy of our website in the directory we use on our
+server (`/var/www/websitefiles/`):
+
+```sh
+❌ rsync -rtvzP ~/websitefiles/ root@example.org:/var/www/websitefiles/
+```
+
+This will *not actually do quite what we want*. It will take our local
+`websitefiles` directory and put it *inside* `websitefiles` on the
+remote machine, ending up with `/var/www/websitefiles/websitefiles`.
+
+Instead, remove the trailing slash from the remote server location:
+
+```sh
+βœ… rsync -rtvzP ~/websitefiles/ root@example.org:/var/www/websitefiles
+```
+
+`websitefiles/` has been replaced with `websitefiles`, and this will do
+what we want.
+
+## Downloading files with rsync {#downloading-file-with-rsync}
+
+You may just as easily download files and directories from your server
+with rsync:
+
+```sh
+rsync -rtvzP root@example.org:/path/to/file /path/to/file
+```
+
+If you don't keep a local copy of your website or other things saved on a serverπŸ”’, it might be a good idea to set up a [cronjob](/cron) or just a normal script on your local computer that takes back-ups of your website in case of server failure!
diff --git a/content/searxng.md b/content/searxng.md
new file mode 100644
index 0000000..7e0c570
--- /dev/null
+++ b/content/searxng.md
@@ -0,0 +1,148 @@
+---
+title: "SearXNG"
+date: 2022-05-16
+icon: 'searxng.svg'
+tags: ['service']
+short_desc: 'Polls dozens of search engines to give you private and complete search results.'
+---
+
+SearXNG is a free internet metasearch engine which aggregates results
+from more than 70 search services. This guide sets up a working instance
+that can be accessed using a domain over HTTPS. Features include:
+
+- Self-hosted
+- No user tracking
+- No user profiling
+- About 70 supported search engines
+- Easy integration with any search engine
+- Cookies are not used by default
+- Secure, encrypted connections (HTTPS/SSL)
+
+## Installation
+
+"For the installation procedure, use a sudoer login to run the scripts. If you install from root, take into account that the scripts are creating a searx, a filtron and a morty user. In the installation procedure these new created users do need read access to the clone of searx, which is not the case if you clone into a folder below /root." - SearXNG Docs
+
+Install the required packages.
+
+```sh
+apt install git nginx -y
+```
+
+Open http and https ports.
+
+```sh
+iptables -I INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT
+iptables -I INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT
+netfilter-persistent save
+ufw allow 80
+ufw allow 443
+```
+
+Clone the SearXNG Repository.
+
+```sh
+git clone https://github.com/searxng/searxng searxng
+cd searxng
+```
+
+Installing SearXNG, Filtron and Morty.
+
+```sh
+./utils/searx.sh install all
+./utils/filtron.sh install all
+./utils/morty.sh install all
+```
+
+Check that both filtron and morty are running.
+
+```sh
+systemctl status filtron
+systemctl status morty
+```
+
+## Configure Nginx
+
+Create a new file `/etc/nginx/sites-available/searxng.conf` and add the
+following:
+
+```nginx
+server {
+
+ # Listens on http
+ listen 80;
+ listen [::]:80;
+
+ # Your server name
+ server_name searx.example.org;
+
+ # If you want to log user activity, comment these
+ access_log /dev/null;
+ error_log /dev/null;
+
+ # Searx reverse proxy
+ location / {
+ proxy_pass http://127.0.0.1:4004/;
+
+ proxy_set_header Host $host;
+ proxy_set_header Connection $http_connection;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Scheme $scheme;
+ proxy_set_header X-Script-Name /searx;
+ }
+
+ location /searx/static {
+ alias /usr/local/searx/searx-src/searx/static;
+ }
+
+ # Morty reverse proxy
+ location /morty {
+ proxy_pass http://127.0.0.1:3000/;
+
+ proxy_set_header Host $host;
+ proxy_set_header Connection $http_connection;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Scheme $scheme;
+ }
+}
+```
+
+
+Now create a symbolic link to enable this site.
+
+```sh
+ln -s /etc/nginx/sites-available/searxng.conf /etc/nginx/sites-enabled/searxng.conf
+```
+
+Restart Nginx and SearXNG.
+
+```sh
+systemctl restart nginx
+service uwsgi restart searx
+```
+
+## Configure HTTPS with Certbot
+
+Install certbot.
+
+```sh
+apt install python3-certbot-nginx
+```
+
+Install a Let\'s Encrypt SSL certificate to Nginx and optionally let it
+configure HTTPS for you. [Detailed instructions and additional information](/basic/certbot).
+
+```sh
+certbot --nginx
+```
+
+SearXNG should now be available from your domain.
+
+## Configuration
+
+You can change settings by editing `/etc/searxng/settings.yml`.
+
+## Contribution
+
+Author: goshawk22 -- [website](https://goshawk22.uk)
diff --git a/content/selfhosting.md b/content/selfhosting.md
new file mode 100644
index 0000000..0aa00b2
--- /dev/null
+++ b/content/selfhosting.md
@@ -0,0 +1,202 @@
+---
+title: "Self hosting"
+date: 2020-08-19
+tags: ['server']
+---
+## Introduction
+
+When you have a(n old) computer lying around, and you have cheap
+electricity and a good internet connection, self hosting might be a good
+option for you.
+
+### Why would you choose selfhosting?
+
+- You have control over the hardware, and you can upgrade your server
+ in the future. For example: if you host a file server and your hard
+ drive goes full, you can simply add another hard drive or upgrade
+ it.
+- No bandwith limits, storage limits, etc. (some VPSes have this)
+- It **can** be cheaper than using a VPS. This only is the case if you
+ got the server for really cheap and your electricity is cheap.
+- You can have a media server to consoom your content (for example
+ with `Jellyfin`). You can technically do this on a VPS, but that
+ will be more expensive than self hosting. If you have a media
+ server, you can stream media from your server to more devices. (I
+ recommend just downloading it on your device, but if you have
+ multiple devices, this could be a good solution)
+
+### Downsides
+
+Some possible downsides of choosing to host at home could be:
+
+- Your ISP not approving of what you\'re doing. Some ISP\'s do not
+ condone you hosting at home. Usually when this is the case, it could
+ be harder if you want to forward ports, or it could be impossible to
+ get a static IP address. Check your ISP\'s terms of service.
+ Sometimes, it will say that hosting a webserver, email server, and
+ more, is not allowed.
+- This can also include blocked ports. ISPs can block certain ports to
+ the world. Sometimes ISPs only block 445/139 (which is for the
+ better as Samba, using these ports isn\'t really secure and it\'s
+ outdated). But some ISPs (sadly) block crucial ports like 80
+ and/or 443. You need to check this before trying anything. If this
+ is the case, a way to get around it is to get another ISP or use an
+ alternative port. A great website to check this is:
+ [canyouseeme.org](https://canyouseeme.org/). You can also check if
+ you did the port forwaring correctly here.
+- Security. Opening your network to the public could bring security
+ risks. For example, never open a Samba server to the public, because
+ it\'s a pretty old protocol, and it has some security
+ vulnerabilities. Be sure you are forwarding the right port, and
+ don\'t just forward random ports to the internet. Also, if you are
+ getting DDoSed, your ISP will temporarily shut down your whole
+ internet connection.
+- When setting up an email server, it can be way harder to not have
+ your email show up as spam in other\'s people email. If you use a
+ VPS, this is way easier.
+- Space, power consumption and noise. Of course, this differs per
+ server.
+
+Your mileage may vary, go and check each of these points, and see if
+selfhosting is the right choice for you. Try and calculate your power
+consumption and see if your electricity cost is not too expensive.
+
+For me, the upsides outweighed the downsides, which is why I chose to
+host at home. But, this differs with each person and scenario. Go and
+research what your exact situation is, before trying anything. Otherwise
+you\'ll have to face some bad surprises.
+
+## Hardware
+
+### What kind of hardware should you choose?
+
+If you pay your own electricity bill, power consumption is a big factor.
+Most old laptop computers are ideal in the sense that they don\'t use a
+lot of power, and if the battery still works, you have a built-in UPS!
+The bad thing is, most old laptop computers aren\'t that powerful, and
+they lack in upgradability. (you shouldn\'t really be using anything
+older than 2006, and I recommend at least a performance equivalant of a
+Core 2 CPU)
+
+If you can find an energy efficient desktop (under 100W), that is a
+great option. They are pretty upgradable and they don\'t use a lot of
+power. They can also be pretty cheap, but old laptops are usually
+cheaper. If you can afford new hardware, and are willing to build a PC,
+you can find really power effecient CPU/motherboard combos, and they can
+be cheap, for example the Celeron J3060. I recommend a low wattage power
+supply or an effecient one for these kinds of builds. Pico PSUs are
+pretty tiny and efficient solutions in these builds.
+
+Of course, if you don\'t pay your electricity bill or cost is not a
+problem for you, you can use just about any old desktop (as long as
+it\'s not from the 90\'s, I recommend at least a Core 2 chip again, or
+an Athlon 64 X2).
+
+### Usecases
+
+Of course, hardware choices depend on the usecase. The above
+recommendations I gave you work fine for e-mail server, webserver and
+fileserver types of applications, but they will struggle to transcode
+video if you are going to host a media server. You\'ll need a faster
+CPU, but also a faster GPU. As an example, the Athlon 200GE or 3000G are
+good and efficient choices for these builds. They are decent CPUs, but
+also have a built in GPU that will transcode video just fine.
+
+If you need a lot of storage, go for a case with a lot of mounts for
+hard drives, this way you can easily mount multiple hard drives. Pros of
+multiple hard drives are redundancy and speed. Cons could be that they
+create more heat and noise. You can\'t use a laptop if you want multiple
+drives, except if you use a hard drive caddy for the CD/DVD drive bay.
+Some business laptops even support RAID 1 (redundancy) and RAID 0 (speed
+and more storage, but you lose your files if one hard drive breaks) this
+way.
+
+## Getting started
+
+### Installing Debian
+
+Once you have the machine, you can install the OS. I recommend Debian,
+as all of the guides on this website are Debian specific. Debian just
+werks as a server OS.
+
+You\'ll need to burn a Debian install image onto a USB flash drive or a
+CD. You can download the image
+[here](https://www.debian.org/CD/netinst/), and you can also find
+information on how to burn the image onto a USB flash drive or CD there.
+
+While installing Debian, do not install any desktop environment. But
+install an SSH server when you get the chance. Also leave webserver
+unchecked, even if you want to use it as a webserver. You\'ll have a
+chance to install this later.
+
+### Port forwaring
+
+Every time you are going to set up a new server program, you need to
+forward a port corresponding to that program. For example, HTTP is port
+80, HTTPS is 443, etc. You need to set this up on your router\'s NAT
+settings (sometimes just called port forwarding, this differs per
+router). These steps differ for each router. Refer to your routers
+manual. A simple command to see what your servers IP address is, is to
+run `ifconfig` on your server. This shows a lot of network info, but it
+will also show your local IP address needed for port forwarding.
+
+Basic ports:
+
+- SSH: port 22 (open this port if you want to admin your server
+ outside your network)
+- HTTP: port 80 (open this port if you want basic webserver
+ functionality)
+- HTTPS: port 443 (you should open this port if you are setting up a
+ webserver because encryption)
+
+### Static or dynamic IP address
+
+If you want to host your server at home, make sure you have a static IP
+address, or you can change your dynamic IP address to a static one.
+Refer to your router settings, some ISPs will have options on this here.
+If you can\'t find anything on this, get in touch with your ISP.
+
+Once you\'ve made sure you have a static IP address, you can find out
+what the IP address is with various websites. You can use a search
+engine to easily find this out. Write this down as you\'ll need it
+later.
+
+Once you\'re done, you can pretty much follow every guide on this
+website, the only difference is that you\'ll need to forward the ports
+you\'ll be using for the server.
+
+### Finding the ports you\'ll need to forward
+
+If you need to know what port you\'ll need to forward, there\'s a
+command for that. Just type `netstat -tulpn` in your servers command
+line. If you want to see the name of the programs, you need to run it as
+a root user. You can do this by putting `sudo` before the command.
+
+```txt
+Local Address State PID/Program name
+0.0.0.0:25 LISTEN 887/master
+0.0.0.0:1883 LISTEN 22452/mosquitto
+0.0.0.0:445 LISTEN 798/smbd
+0.0.0.0:993 LISTEN 381/dovecot
+127.0.0.1:3306 LISTEN 560/mysqld
+0.0.0.0:587 LISTEN 887/master
+0.0.0.0:139 LISTEN 798/smbd
+127.0.1.1:12301 LISTEN 412/opendkim
+0.0.0.0:143 LISTEN 381/dovecot
+0.0.0.0:465 LISTEN 887/master
+0.0.0.0:22 LISTEN 472/sshd
+:::25 LISTEN 887/master
+:::443 LISTEN 1769/apache2
+:::1883 LISTEN 22452/mosquitto
+:::445 LISTEN 798/smbd
+```
+
+*Example output*
+
+In this example, if you need to find the port number from `dovecot`, you
+can look for it in the `Program name` column. Then you can see in the
+local address column that the reported local address is `0.0.0.0:993`.
+You need to look for the part after the semicolon. In this case it\'s
+993. So you\'ll need to forward port 993.
+
+*Written by [hiddej](https://github.com/hidde-j)*
diff --git a/content/sshkeys.md b/content/sshkeys.md
new file mode 100644
index 0000000..f1c8c0d
--- /dev/null
+++ b/content/sshkeys.md
@@ -0,0 +1,153 @@
+---
+title: "Log on with SSH Keys"
+date: 2021-06-29
+tags: ['server']
+---
+Let\'s generate and use SSH keys on our computer. This allows us to
+ensure our identity better than a password ever could. This allows us to
+do two main things:
+
+1. **Password-less login**: With SSH keys, we can permanently designate
+ our profile on our local computer as safe for our server, allowing
+ us to bypass password verification when logging into our server.
+2. **Prevent hacking**: Since we no longer need a password to log in,
+ we can simply deactivate password logins on our server altogether,
+ which prevents hacking from people who may be so lucky as to guess
+ our password!
+
+In other words, using an SSH key to login is **both safer, faster and
+easier**.
+
+This is especially useful once you start making scripts on your computer
+that interact with your server. You can upload files in the background,
+edit your spam filters or anything else from your local computer without
+having to input your password each time you touch the server.
+
+## Generate an SSH key pair
+
+Generating an SSH key is simple. Just run:
+
+```sh
+ssh-keygen
+```
+
+It will prompt you for several options and you can generally chose the
+default options in each case. It will ask you to optionally include a
+password on your SSH key. I generally recommend against this unless you
+happen to be using a computer where you don\'t have root access but
+someone else does (it does minimize the ease of using an SSH key in our
+case).
+
+### What does this SSH key do?
+
+Now whenever you use `ssh` to log into a server, you have the public key
+of this SSH key pair as your identifier. You can tell your server to
+trust this key and it will automatically allow password-less logins from
+this computer.
+
+### Backing up your key
+
+We will do that momentarily, but first, I recommend you backup your
+newly generated key if you plan to use it. If we disable logins to this
+one key and then lose the key, we might be locked out of our server.
+
+I suggest copying your entire `~/.ssh/` directory (user-specific) to a
+USB drive and storing it securely. You may also copy it to the same
+place on another computer to use the key there.
+
+## Making your server trust your key.
+
+Now that you have generated an SSH key, just run the following:
+
+```sh
+ssh-copy-id root@yourdomain.com
+```
+
+The command will ask for your server\'s root password and log you in
+briefly. What this does is that it puts your public SSH key fingerprint
+on your server in a file `/root/.ssh/authorized_keys`. This file in turn
+allows approved SSH keys to log in without passwords.
+
+Note that you can also replace **root** with a username of an account on
+the server if you had made a non-root user that you\'d like to easily
+log into as well. For the username **user**, it will also store the key
+in `/home/user/.ssh/authorized_keys`.
+
+To test if this has worked, now try logging in normally to your server
+with ssh:
+
+```sh
+ssh root@yourdomain.com
+```
+
+It should now let you log in without a password prompt!
+
+If you find that this does not work try running the following, make sure
+you are in the directory where the keys where created.
+
+```sh
+chmod 700 ~/.ssh/
+chmod 644 ~/.ssh/id_rsa.pub
+chmod 600 ~/.ssh/id_rsa
+chmod 644 ~/.ssh/authorized_keys
+```
+
+For whatever reason these files due not have the correct permissions
+set, as ssh is very picky about correct file permissions this can cause
+errors. The above will fix these.
+
+## Disabling Password Logins for Security
+
+Once we have authorized ssh keys for all the devices we need, we can
+actually just disable password logins. If you\'ve ever looked at your
+system logs (`journalctl -xe`) you will find that there are always
+hundreds of random Chinese computers trying to brute force every server
+connected to the internet with random passwords. They are usually
+unsuccessful, but let\'s make it **impossible** for them.
+
+Log into your server and open the `/etc/ssh/sshd_config` file. Here we
+can set settings for our SSH daemon that receives SSH requests.
+
+Now find, uncomment or create the following three lines and set them all
+to **no**:
+
+```sh
+PasswordAuthentication no
+ChallengeResponseAuthentication no
+UsePAM no
+```
+
+Once we\'ve done that, we will reload our SSH daemon:
+
+```sh
+systemctl reload sshd
+```
+
+### We\'re done!
+
+Now you can log in quickly and password-less-ly to your server, despite
+the fact that it is now more secure than ever!
+
+With these settings, even if a hacker steals or perfectly guesses an
+account password, they still cannot log in without an approved SSH key!
+
+## What if I lose my SSH key?!
+
+Firstly, don\'t do this. Take every precaution that you have a backup.
+
+If this does happen, Vultr and most other VPS providers will have a way
+out. Log onto their website and select the server you want to log into.
+
+{{< img src="/pix/ssh-01.png" alt="vultr login" >}}
+
+In the image above, to the right of your VPS name are a series of icons.
+Click on the computer screen-like icon which is the leftmost one.
+
+This will open up a browser window emulating a terminal and you can
+always login with your password here, since logins here count as being
+local---they do not use SSH and therefore can indeed validate with
+your password even if you have disabled it over SSH.
+
+From here, simply reverse the settings we set above and you can log in
+via SSH with a password and reapprove a newly created SSH key or
+whatever you want to do.
diff --git a/content/standalone.md b/content/standalone.md
new file mode 100644
index 0000000..c466465
--- /dev/null
+++ b/content/standalone.md
@@ -0,0 +1,40 @@
+---
+title: "Certbot on Standalone Domains and Subdomains"
+date: 2021-07-02
+tags: ['server']
+---
+
+The command `certbot --nginx` will take an unencrypted website on an
+Nginx configuration file, get a certificate for it and change the
+configuration to use that certificate and thus HTTPS.
+
+Sometimes, however, you are given an Nginx configuration template that
+already has encryption/HTTPS, so running the automated `certbot --nginx`
+is not possible, as it will simply give an error saying that the
+certicate that Nginx is looking for doesn\'t already exist and thus the
+Nginx config is broken.
+
+So suppose you want to get a certificate for **pleroma.example.org**
+because you are installing Pleroma and the configuration file
+presupposes a certificate. In this case you would want to run this:
+
+```sh
+systemctl stop nginx
+certbot certonly --standalone -d pleroma.example.org
+systemctl start nginx
+```
+
+What we do here is temporarily turn of Nginx, then run a `certonly`
+subcommand that generates a certificate for the domain without changing
+or caring about the Nginx configuration. Then we reactivate Nginx, thus
+turning back on our webserver.
+
+The reason we deactivate Nginx is that it uses the ports that Certbot
+will want to bind to, and thus we must temporarily turn Nginx off to let
+Certbot use those ports. (What it actually does is spin up a dummy
+webserver that doesn\'t need to think about the Nginx configuration.)
+
+This is just a little note of something that might confuse people, but
+the three commands above should suffice. If your site is still managed
+by Nginx, it should still be able to renew with simple
+`certbot renew --nginx` without a problem.
diff --git a/content/tor.md b/content/tor.md
new file mode 100644
index 0000000..c12fa92
--- /dev/null
+++ b/content/tor.md
@@ -0,0 +1,119 @@
+---
+title: "Tor"
+date: 2021-06-30
+icon: 'tor.svg'
+tags: ['service']
+short_desc: "Set your site up privately on the 'dark web.'"
+---
+
+Now that you have a website, why not offer it on a private alternative
+such as the onion network?
+
+## Setting up Tor
+
+### Installing Tor
+
+First, we need to ensure that our CPU architecture is supported. Ensure
+that it is either amd64, arm64, or i386:
+
+ dpkg --print-architecture
+
+We need to [add the Tor repos to our
+system](https://support.torproject.org/apt/tor-deb-repo/) to get the
+latest version of Tor:
+
+ apt install -y apt-transport-https gpg
+ echo "deb [signed-by=/usr/share/keyrings/tor-archive-keyring.gpg] https://deb.torproject.org/torproject.org $(lsb_release -cs) main
+ deb-src [signed-by=/usr/share/keyrings/tor-archive-keyring.gpg] https://deb.torproject.org/torproject.org $(lsb_release -cs) main" > /etc/apt/sources.list.d/tor.list
+
+Then we need to add the GPG keys to our keyring:
+
+ curl -s https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | gpg --dearmor > /usr/share/keyrings/tor-archive-keyring.gpg
+
+Now install Tor:
+
+ apt update
+ apt install tor deb.torproject.org-keyring
+
+### Enabling Tor
+
+Next edit the file `/etc/tor/torrc`, uncommenting the following lines:
+
+ HiddenServiceDir /var/lib/tor/hidden_service/
+ HiddenServicePort 80 127.0.0.1:80
+
+#### Optional: Running multiple onion services
+
+If you want to forward multiple virtual ports for a single onion
+service, just add more HiddenServicePort lines (replace the 80 with any
+unoccupied port).
+
+If you want to run multiple onion services from the same Tor client,
+just add another HiddenServiceDir line.
+
+Now start and enable Tor at boot:
+
+ systemctl enable --now tor
+
+If the next command outputs "active" in green you\'re golden!
+
+ systemctl status tor
+
+Now your server is on the dark web. The following command will give you
+your onion address:
+
+ cat /var/lib/tor/hidden_service/hostname
+
+## Adding the Nginx Config
+
+From here, the steps are almost identical to setting up a normal website
+configuration file. Follow the steps as if you were making a new website
+in the webserver [tutorial](/basic/nginx) up until the server block of
+code. Instead, paste this:
+
+ server {
+ listen 127.0.0.1:80 ;
+ root /var/www/landchad ;
+ index index.html ;
+ server_name your-onion-address.onion ;
+ }
+
+#### Clarification
+
+Nginx will listen on port 80 for your *server\'s* localhost.
+
+The `root` line is the path to whichever website of yours you\'d like to
+mirror.
+
+Now we are almost done, all we have to do is enable the site and reload
+nginx which, is also covered in [the webserver
+tutorial](nginx.html#enable).
+
+### Advertise your onion service
+
+You can add the Onion-Location header to your normal website to
+advertise your onion service to Tor users. On your regular site\'s nginx
+config, add the following line:
+
+ server {
+ ...
+ add_header Onion-Location http://your-onion-address.onion$request_uri;
+ }
+
+After doing this and reloading nginx, when visiting your regular site
+via Tor, you should see a \".onion available\" button on the address
+bar, which should take you to the onion service.
+
+### Update regularly!
+
+Make sure to update Tor on a regular basis by running:
+
+ apt update
+ apt install tor
+
+#### Note:
+
+You do [not]{.underline} need to run certbot for an ssl certificate.
+HTTP over tor is plenty secure!
+
+**Contributor** - [tomfasano.net](https://tomfasano.net)
diff --git a/content/ufw.md b/content/ufw.md
new file mode 100644
index 0000000..52cd294
--- /dev/null
+++ b/content/ufw.md
@@ -0,0 +1,223 @@
+---
+title: "Using UFW as a Firewall"
+date: 2021-06-30
+tags: ['server']
+---
+**Uncomplicated Firewall** (UFW) is a front-facing program for the more
+involved `iptables` firewall program installed in most GNU/Linux
+distributions. We can use `ufw` to restrict machines on the internet to
+only access the services (SSH, websites etc) you want them to, but it
+can also be used to prevent programs on the computer itself from
+accesing parts of the internet it shouldn\'t.
+
+## How to Get It
+
+Log into your server by pulling up a terminal and typing:
+
+```sh
+ssh root@example.org
+```
+
+This command will attempt to log into your server and run a remote
+shell. If you leave the settings default, it should prompt you for your
+password, and you can just copy or type in the password from Vultr\'s
+site.
+
+Some VPS providers automatically install `ufw`, but if you do not have
+it installed already, install it in the typical way:
+
+```sh
+apt install ufw
+```
+
+## First-Time Setup
+
+You can check the status of `ufw` right now by running:
+
+```sh
+ufw status
+```
+
+Without any changes, it should report back `Status: inactive`. Let\'s
+set it up so that only connections to SSH (standardized at port 22) are
+allowed in, and then enable the firewall:
+
+**Careful!** Enabling `ufw` without allowing SSH will block you from
+remoting to your server. Double-check that you have allowed SSH, and if
+you have changed the default SSH port, put in *that* number instead.
+
+```sh
+ufw default deny incoming # block all incoming connections by default
+ufw allow in ssh # or: ufw allow in 22
+ufw enable
+```
+
+`ufw` has an internal list of protocols applications, and the ports used
+by them. In this case, it knows SSH is on port 22. We\'ll go more in
+detail how to view all protocols `ufw` knows about. By default, when you
+allow an incoming port, it allows that port both on IPv4 and IPv6.
+
+With the firewall enabled and allowing only SSH in, all other ports are
+protected from incoming requests. To view all your rules, run:
+
+```sh
+ufw status verbose
+```
+
+A firewall that allows to connect to SSH and their website may look
+like:
+
+```txt
+Status: active
+Logging: on (low)
+Default: deny (incoming), allow (outgoing), deny (routed)
+New profiles: skip
+
+To Action From
+-- ------ ----
+22 (SSH) ALLOW IN Anywhere
+80,443/tcp (WWW Full) ALLOW IN Anywhere
+22 (SSH (v6)) ALLOW IN Anywhere (v6)
+80,443/tcp (WWW Full (v6)) ALLOW IN Anywhere (v6)
+```
+
+If you want to delete e.g. the \'WWW Full\' rule, run:
+
+```sh
+ufw delete allow in 'WWW Full'
+ufw reload
+```
+
+## Enabling Common Services
+
+You have blocked all incoming ports but SSH, which means no outsiders
+would be able to access other services, like an email server or your
+website. You should look at the ports your services are open on and
+enable them individually. Here is a list of a few common services:
+
+### Opening Port Numbers
+
+Suppose you install [a Gemini server](/gemini), which must broadcast
+on port 1965. By default `ufw` blocks all incoming connections on all
+ports, so whenever you install a new service like this you will have to
+tell `ufw` to enable the desired port:
+
+```sh
+ufw allow 1985
+```
+
+### Websites: HTTP and HTTPS
+
+HTTP uses port 80 and HTTPS uses port 443. We can enable them like this:
+
+```sh
+ufw allow 80
+ufw allow 443
+```
+
+But `ufw` additionally knows the typical ports of common serives, so you
+can also run this:
+
+```sh
+ufw allow http
+ufw allow https
+```
+
+And that will do the same thing. There are also other abbreviations for
+common port lists:
+
+```sh
+ufw allow in 'WWW Full'
+```
+
+To see these other \"apps\" that `ufw` knows by default, run
+`ufw app list`
+
+### Email: IMAP, POP3, and SMTP
+
+```sh
+ufw allow in IMAPS
+ufw allow in POP3
+ufw allow in SMTP
+ufw allow in 'Postfix SMTPS'
+ufw allow in 'Mail Submission'
+```
+
+## Fine-Tuning Rules
+
+Instead of denying all ports by default, you may want to deny (ignores
+incoming requests) or reject (explicitly tells requests they\'re not
+allowed):
+
+```sh
+ufw default allow in
+ufw deny in PORT
+ufw reject in PORT
+ufw reload
+```
+
+You can add rules to comments to remember what they are there for:
+
+```sh
+ufw allow in PORT comment 'Secret SSH'
+ufw reload
+ufw status verbose
+```
+
+Output:
+
+```txt
+To Action From
+-- ------ ----
+PORT ALLOW IN Anywhere # Secret SSH
+PORT (v6) ALLOW IN Anywhere (v6) # Secret SSH
+```
+
+To deny outgoing ports:
+
+```sh
+ufw deny out PORT
+```
+
+Ratelimiting is useful to protect against brute-force login attacks,
+like in SSH. Only IPv4 is supported for now. Enable it by running:
+
+```sh
+ufw limit PORT/tcp
+```
+
+To blocklist IP addresses:
+
+```sh
+ufw deny from IP_ADDRESS
+```
+
+To read more what you can do with `ufw`, run:
+
+```sh
+man ufw
+```
+
+## Recovering SSH {#recovering-from-losing-ssh}
+
+If you have accidentally firewalled yourself from logging on your
+computer, you can recover access by using your VPS\'s virtual console.
+On Vultr, this is on your VPS\'s menu. To the right of the server name,
+It is the leftmost icon that looks like a monitor.
+
+{{< img src="/pix/ssh-01.png" link="/pix/ssh-01.png" alt="View Console" >}}
+
+Log in through there, and disable ufw by typing:
+
+```sh
+ufw disable
+```
+
+## Further Reading
+
+- `man ufw` πŸ‘ˆ
+- [Ubuntu Wiki:
+ UncomplicatedFirewall](https://wiki.ubuntu.com/UncomplicatedFirewall)
+- [Gufw (Graphical UFW)](https://help.ubuntu.com/community/Gufw)
+
+**Contributor** - [shunter.xyz](https://shunter.xyz)
diff --git a/content/yarr.md b/content/yarr.md
new file mode 100644
index 0000000..6882fa1
--- /dev/null
+++ b/content/yarr.md
@@ -0,0 +1,101 @@
+---
+title: "Yarr"
+date: 2022-07-01
+icon: 'yarr.svg'
+tags: ['service']
+short_desc: 'A self-hosted, web-based feed aggregator'
+---
+
+[Yarr](https://github.com/nkanaev/yarr) (yet another rss reader) is a web-based feed aggregator which can be used both as a desktop application and a personal self-hosted server.
+
+It is written in Go with the frontend in Vue.js. The storage is backed by SQLite.
+
+## Installing Yarr
+
+Firstly, we have to download yarr binary from github on our system
+
+```sh
+wget https://github.com/nkanaev/yarr/releases/download/v2.3/yarr-v2.3-linux64.zip
+```
+
+Unzip the archive
+
+```sh
+unzip -x yarr-v2.3-linux64.zip
+```
+
+Move the binary to your bin folder
+
+```sh
+mv yarr /usr/local/bin/yarr
+```
+
+## Configuration
+
+Now we need to create a `auth.conf` file that include user and password to create a local yarr account.
+I personnaly store this file in a directory called yarr in `~/.config` folder, but you can place the file wherever you want.
+
+```sh
+mkdir ~/.config/yarr
+echo 'landchad:password' > ~/.config/yarr/auth.conf
+```
+
+## Creating a service
+
+Create a new file /etc/systemd/system/yarr.service and add the following:
+
+```systemd
+[Unit]
+Description=Yarr
+
+[Service]
+Environment=HOME=/home/landchad
+ExecStart=/usr/bin/env yarr -addr 0.0.0.0:7070 -auth-file=/home/landchad/.config/yarr/auth.conf -db=/home/landchad/.config/yarr/feed.sql -log-file=/home/landchad>/.config/yarr/access.log
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
+```
+
+After creating the config, load, start and enable the service with the following commands.
+
+```sh
+systemctl daemon-reload
+systemctl enable --now yarr
+```
+
+## Nginx configuration
+Create an Nginx configuration file for Yarr, say /etc/nginx/sites-available/yarr and add the content below:
+
+```nginx
+server {
+ listen 80 ;
+ listen [::]:80 ;
+
+ server_name rss.example.org ;
+
+ location / {
+ proxy_pass http://localhost:7070/;
+ }
+}
+```
+
+Now let's enable the Nginx Yarr site and reload Nginx to make it active.
+
+```sh
+ln -s /etc/nginx/sites-available/yarr /etc/nginx/sites-enabled
+systemctl reload nginx
+```
+
+### Encryption
+
+You can encrypt your yarr subdomain as well. Let's do that with certbot:
+
+```sh
+certbot --nginx -d rss.example.org
+```
+
+Now you can go to rss.example.org, login and start to add your feeds!
+
+## Contribution
+Author: Jppaled -- [jppaled.xyz](https://jppaled.xyz) \-- XMR: `86bVp8bcx1F3y3NsfuTRs6D7FfnDyLomV7dLJmus2YMiY9Aat6W5m8JGwuvH39HKrq3immS7noKq8HeW4gb4BFbyLoz5WSZ`{.crypto}