\documentclass[DIV=12,%
               BCOR=10mm,%
               headinclude=false,%
               footinclude=false,open=any,%
               fontsize=11pt,%
               twoside,%
               paper=210mm:11in]%
               {scrbook}






\usepackage[noautomatic]{imakeidx}



\usepackage{microtype}
\usepackage{graphicx}
\usepackage{alltt}
\usepackage{verbatim}
\usepackage[shortlabels]{enumitem}
\usepackage{tabularx}
\usepackage[normalem]{ulem}
\def\hsout{\bgroup \ULdepth=-.55ex \ULset}
% https://tex.stackexchange.com/questions/22410/strikethrough-in-section-title
% Unclear if \protect \hsout is needed. Doesn't looks so
\DeclareRobustCommand{\sout}[1]{\texorpdfstring{\hsout{#1}}{#1}}
\usepackage{wrapfig}

% avoid breakage on multiple <br><br> and avoid the next [] to be eaten
\newcommand*{\forcelinebreak}{\strut\\*{}}

\newcommand*{\hairline}{%
  \bigskip%
  \noindent \hrulefill%
  \bigskip%
}

% reverse indentation for biblio and play

\newenvironment*{amusebiblio}{
  \leftskip=\parindent
  \parindent=-\parindent
  \smallskip
  \indent
}{\smallskip}

\newenvironment*{amuseplay}{
  \leftskip=\parindent
  \parindent=-\parindent
  \smallskip
  \indent
}{\smallskip}

\newcommand*{\Slash}{\slash\hspace{0pt}}


% http://tex.stackexchange.com/questions/3033/forcing-linebreaks-in-url
\PassOptionsToPackage{hyphens}{url}\usepackage[hyperfootnotes=false,hidelinks,breaklinks=true]{hyperref}
\usepackage{bookmark}

\usepackage[english,shorthands=off]{babel}
\babelfont{rm}[Path=/usr/share/fonts/opentype/linux-libertine/,%
 BoldFont=LinLibertine_RB.otf,%
 BoldItalicFont=LinLibertine_RBI.otf,%
 ItalicFont=LinLibertine_RI.otf]{LinLibertine_R.otf}
\babelfont{tt}[Scale=MatchLowercase,%
 Path=/usr/share/fonts/truetype/cmu/,%
 BoldFont=cmuntb.ttf,%
 BoldItalicFont=cmuntx.ttf,%
 ItalicFont=cmunit.ttf]{cmuntt.ttf}
\babelfont{sf}[Scale=MatchLowercase,%
 Path=/usr/share/fonts/truetype/cmu/,%
 BoldFont=cmunsx.ttf,%
 BoldItalicFont=cmunso.ttf,%
 ItalicFont=cmunsi.ttf]{cmunss.ttf}



\renewcommand*{\partpagestyle}{empty}


% global style

\pagestyle{plain}




\usepackage{indentfirst}

% remove the numbering
\setcounter{secnumdepth}{-2}

% remove labels from the captions
\renewcommand*{\captionformat}{}
\renewcommand*{\figureformat}{}
\renewcommand*{\tableformat}{}
\KOMAoption{captions}{belowfigure,nooneline}
\addtokomafont{caption}{\centering}







\deffootnote[3em]{0em}{3em}{\textsuperscript{\thefootnotemark}~}


\addtokomafont{disposition}{\rmfamily}
\addtokomafont{descriptionlabel}{\rmfamily}


\frenchspacing
% avoid vertical glue
\raggedbottom

% this will generate overfull boxes, so we need to set a tolerance
% \pretolerance=1000
% pretolerance is what is accepted for a paragraph without
% hyphenation, so it makes sense to be strict here and let the user
% accept tweak the tolerance instead.
\tolerance=200
% Additional tolerance for bad paragraphs only
\setlength{\emergencystretch}{30pt}

% (try to) forbid widows/orphans
\clubpenalty=10000
\widowpenalty=10000





% given that we said footinclude=false, this should be safe
\setlength{\footskip}{2\baselineskip}
\setlength{\parindent}{15pt}

\title{Resilient by Design}
\date{}
\author{The Techno Anarchist}
\subtitle{A Complete Guide to Decentralized, Private \& Censorship-Resistant Technology From First Principles to Running Infrastructure}






% https://groups.google.com/d/topic/comp.text.tex/6fYmcVMbSbQ/discussion
\hypersetup{%
pdfencoding=auto,
pdftitle={Resilient by Design},%
pdfauthor={The Techno Anarchist},%
pdfsubject={A Complete Guide to Decentralized, Private \& Censorship-Resistant Technology From First Principles to Running Infrastructure},%
pdfkeywords={}%
}


\begin{document}









  \begin{titlepage}


  \strut\vskip 2em
  \begin{center}

  {\usekomafont{title}{\huge Resilient by Design\par}}%
  \vskip 1em
  
  {\usekomafont{subtitle}{A Complete Guide to Decentralized, Private \& Censorship-Resistant Technology From First Principles to Running Infrastructure\par}}%
  
  \vskip 2em
  
  {\usekomafont{author}{The Techno Anarchist\par}}%
  
  \vskip 1.5em



   
   \vfill



  
    \strut\par
  


  \end{center}


     \end{titlepage}
     
     \cleardoublepage





\tableofcontents
% start a new right-handed page

\cleardoublepage



\chapter{Preface: Who This Book Is For and How to Use It}


This book was written for two types of readers who share the same goal: building communication infrastructure that cannot be silenced.


\textbf{If you are a complete beginner} — you have never set up a server, you do not know what a VPN really is inside, and phrases like “DHT” or “P2P overlay” mean nothing to you — this book starts from first principles. Every concept is explained before it is used. Look for the blue \emph{Beginner’s Corner} boxes; they are written specifically for you.


\textbf{If you are intermediate} — you know your way around Linux, you have maybe set up a home server — this book gives you the deeper theory and the real configuration examples to build production-grade distributed infrastructure. Look for the purple \emph{Going Deeper} boxes for extra nuance.


\textbf{How this book is organized:} Each chapter follows the same structure. First, \emph{Theory} — the why and how of the concept from first principles. Then, \emph{Application} — the practical steps, configuration examples, and troubleshooting. You can read theory-only on a first pass, then return to application when you are ready to build.


All software described in this book is free, open-source, and used by journalists, researchers, human rights workers, and emergency responders worldwide. Knowledge of how technology works is not a crime anywhere in the world.

\part{Part I — The Threat \& The Strategy}


Understanding why this technology matters and what philosophy guides the entire guide

\chapter{Chapter 1: How Authoritarian Regimes Silence People}

\subsection{Learning Objectives}


\begin{itemize}
\item\relax 
Understand the seven-step playbook that governments use to silence digital communications



\item\relax 
Know which technologies counter each step



\item\relax 
Understand that each suppression technique has a technical counter-measure




\end{itemize}
\section{1.1 The Anatomy of a Digital Crackdown}


When a government decides to suppress its population digitally, it does not flip one switch. It works through a predictable sequence of escalating measures, each targeting a different layer of the communications stack. Understanding this sequence tells you exactly which technologies you need — and in what order of priority.

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|X|}
\hline
\relax  Step  &  What They Do  &  Technical Method  &  Counter-measure   \\
\hline
\relax  1  &  Block social media  &  DNS blocking, IP blocking, deep packet inspection (DPI)  &  VPNs, Tor, DNS-over-HTTPS, self-hosted alternatives   \\
\relax  2  &  Block commercial VPNs  &  Block known VPN server IPs; detect VPN traffic signatures  &  WireGuard (obfuscated), Tor bridges, Shadowsocks   \\
\relax  3  &  Take down news sites  &  DNS removal, hosting provider pressure, IP blacklists  &  IPFS, Hyphanet, Tor onion services, mirrors in other countries   \\
\relax  4  &  Throttle or cut mobile internet  &  ISP-level bandwidth caps, mobile network throttling  &  Wi-Fi mesh (BATMAN-adv), radio communications (APRS, LoRa, HF)   \\
\relax  5  &  Intercept and read messages  &  ISP-level traffic capture, SSL inspection at the ISP, malware on devices  &  End-to-end encryption (Matrix\Slash{}XMPP with OMEMO), Signal, device hardening   \\
\relax  6  &  Identify and locate dissidents  &  IP address tracking, metadata analysis, cell tower triangulation  &  Tor, Yggdrasil, no-log policies, operational security   \\
\relax  7  &  Full internet shutdown (“kill switch”)  &  Order ISPs to stop routing traffic; BGP route withdrawal  &  Radio (HF shortwave, APRS), local mesh networks, satellite terminals   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip


\noindent \textbf{Beginner’s Corner: What is “deep packet inspection”?}


Imagine postal workers who not only check the address on your envelope, but open it, read the letter, and decide whether to deliver it based on the content. DPI does the same thing with internet traffic — it inspects the content of data packets, not just their destination. This is how governments block VPNs (they recognize the “shape” of VPN traffic even if they cannot read the encrypted content). The counter-measure is to disguise VPN traffic so it looks like ordinary web browsing.

\section{1.2 The Infrastructure They Control}


To understand what can be blocked, you must understand what authoritarian governments control:


\begin{itemize}
\item\relax 
\textbf{Internet Service Providers (ISPs)} — In most countries, ISPs must obtain a license. The government can revoke that license or issue legal orders to filter traffic. All internet traffic in a country passes through licensed ISPs.



\item\relax 
\textbf{DNS Resolvers} — Most people’s computers use ISP-provided DNS resolvers. The ISP controls these and can make \texttt{bbc.com} resolve to nowhere, or to a government warning page.



\item\relax 
\textbf{Border Routers} — Every country has a small number of connection points to the global internet (Internet Exchange Points). A government can order these to filter or block traffic.



\item\relax 
\textbf{App Stores and Hosting Providers} — Apple and Google operate app stores in every country. A government can pressure them to remove apps. Similarly, hosting providers operating in a country can be ordered to take down content.



\item\relax 
\textbf{Physical Infrastructure} — Fiber cables, cell towers, and exchange buildings are physical locations that can be raided, damaged, or controlled.




\end{itemize}

\textbf{The key insight:} Everything on this list is centralized. There are specific chokepoints — specific companies, specific buildings, specific people — that a government can pressure. The answer to all of it is \emph{decentralization} — making the system have no chokepoints, no single company, no single building that controls it.


\noindent \textbf{The Optimistic Reality}


Complete internet shutdowns are rare and costly — they damage the economy, disrupt government services, and create international backlash. Most authoritarian regimes aim for selective suppression: block specific sites, monitor specific people, silence specific voices. That is what the tools in this book are primarily designed to counter.

\chapter{Chapter 2: The Strategy — Decentralize Everything}

\subsection{Learning Objectives}


\begin{itemize}
\item\relax 
Understand the core philosophy: eliminate every single point of failure and control



\item\relax 
Learn the three pillars: distribute, encrypt, and diversify



\item\relax 
Understand the layered defense model




\end{itemize}
\section{2.1 The Three Pillars}


\textbf{Pillar 1: Distribute.} Never let any single machine, company, or location be essential to your communications. If the loss of any one component silences your network, that component is a liability. Build so that the loss of any component is automatically compensated for by the others.


\textbf{Pillar 2: Encrypt.} Assume all traffic is observed. Make the contents of that traffic meaningless to observers. End-to-end encryption means the only people who can read a message are the people it is addressed to — not the ISP, not the platform, not the government.


\textbf{Pillar 3: Diversify.} Do not depend on a single communication channel. If Matrix is blocked, use XMPP. If XMPP is blocked, use Tor. If the internet is down, use radio. Diversity means redundancy; redundancy means resilience.

\section{2.2 Layered Defense — Defense in Depth}


Security and resilience professionals use a concept called “defense in depth” — multiple independent layers of protection, so that breaking through one layer does not compromise everything. Think of a medieval castle: a moat, then walls, then an inner keep, then a fortified room. An attacker must breach all layers to reach the treasure.


\begin{alltt}

Layer 1: Physical — Hardware you own, encrypted disks, UPS power backup
         ↓
Layer 2: Network — Firewall, VPN, network segmentation (VLANs)
         ↓
Layer 3: Transport — TLS encryption on all connections
         ↓
Layer 4: Application — End-to-end encrypted messaging (Matrix/XMPP)
         ↓
Layer 5: Anonymity — Tor or I2P to hide who is talking to whom
         ↓
Layer 6: Content — IPFS/Hyphanet so content exists without a location
         ↓
Layer 7: Radio — HF/LoRa/APRS for when all internet is down

\end{alltt}


You do not need all seven layers for every situation. Match your layers to your threat model (which Chapter 25 covers in depth). But understanding all seven tells you where your current gaps are.


\noindent \textbf{Beginner’s Corner: An Analogy for the Whole Book}


Imagine your group needs to communicate secretly during a crackdown. You have a plan:


\begin{enumerate}[1.]
\item\relax 
\textbf{Normally:} Use your private Matrix chat server, encrypted, over a VPN



\item\relax 
\textbf{If Matrix is blocked:} Switch to your private XMPP server on a Tor onion address



\item\relax 
\textbf{If internet is throttled too badly:} Use your local Wi-Fi mesh (BATMAN-adv) to communicate within the city



\item\relax 
\textbf{If everything is cut:} Use handheld radios on prearranged frequencies with Morse code or digital modes




\end{enumerate}

This book teaches you how to build all four of those fallback layers. By the end, losing any one — or even two — of them does not stop you.

\part{Part II — Foundations: How Computers and Networks Work}


The essential theory you need before building anything

\chapter{Chapter 3: Linux — Your Trustworthy Foundation}

\subsection{Learning Objectives}


\begin{itemize}
\item\relax 
Understand why Linux is the foundation for all the infrastructure in this book



\item\relax 
Learn the key Linux concepts: processes, systemd, namespaces, cgroups, logging



\item\relax 
Know how to install and navigate a Linux system for the first time




\end{itemize}
\section{Theory: What Linux Is and Why It Matters}


Linux is a free, open-source operating system kernel — the core software that manages your computer’s hardware and allows other software to run. Unlike Windows (owned by Microsoft) or macOS (owned by Apple), Linux is owned by nobody and everybody. Its source code is publicly available for anyone to read, audit, and modify.


This is not just a philosophical point — it has practical consequences for security and trust:


\begin{itemize}
\item\relax 
\textbf{No hidden backdoors:} Any backdoor in Linux’s source code would be visible to the millions of people who read and audit it. Proprietary operating systems make this kind of independent verification impossible.



\item\relax 
\textbf{No company to pressure:} Microsoft has responded to government requests for data. Apple has removed apps at the request of authoritarian governments. The Linux Foundation has no products to sell in any country, no app store to police.



\item\relax 
\textbf{Complete control:} On Linux, you decide exactly what software runs. Nothing installs itself, nothing phones home, nothing updates without your consent.




\end{itemize}

\noindent \textbf{Beginner’s Corner: Which Linux should I use?}


There are hundreds of Linux “distributions” (distros) — versions of Linux packaged with different software. For beginners, use \textbf{Ubuntu Server 24.04 LTS} or \textbf{Debian 12 (Bookworm)}. Both are stable, widely used, and have excellent documentation. “LTS” means “Long Term Support” — you will receive security updates for years without needing to upgrade.

\section{Theory: The Linux Architecture}


\begin{alltt}

User Applications (Matrix, IPFS, Docker, your scripts)
         ↕
System Libraries (libc, OpenSSL — shared code apps use)
         ↕
System Calls (the API between programs and the kernel)
         ↕
Linux Kernel (manages hardware, memory, processes, network)
         ↕
Hardware (CPU, RAM, disks, network cards)

\end{alltt}

\section{Theory: Processes — Every Running Program}


When a program runs on Linux, it becomes a “process” — an isolated instance of a running program with its own memory space. Every process has:


\begin{itemize}
\item\relax 
A Process ID (PID) — a unique number



\item\relax 
A user it runs as (e.g. \texttt{root} or a limited service account)



\item\relax 
Permissions — what files and resources it can access



\item\relax 
A parent process — most processes are started by another process




\end{itemize}

The key security principle: \textbf{run every service as a non-root user with the minimum permissions it needs.} If your Matrix server is compromised, it should only have access to the Matrix data directory — not to your WireGuard keys, your backup encryption keys, or your monitoring configuration.

\section{Theory: systemd — The Service Manager}


When Linux boots, the first process that starts is \texttt{systemd} (PID 1). It is responsible for starting all other services in the correct order and keeping them running. Think of it as the city manager who makes sure all city services start up in the morning and restarts anything that crashes.


Every service on your system is described by a “unit file” — a configuration file that tells systemd how to start the service, what user to run it as, what to do if it crashes, and what other services it depends on.

\section{Theory: Namespaces and cgroups — How Containers Work}


Two Linux kernel features enable containers:


\textbf{Namespaces} create isolated views of the system. A process inside a namespace sees only the resources in its namespace — its own network interfaces, its own process list, its own filesystem. From inside a container, it looks like you have your own computer.


\textbf{cgroups} (control groups) limit how much of each resource (CPU, memory, disk I\Slash{}O, network) a process or group of processes can use. This prevents one misbehaving service from consuming all resources and crashing everything else.

\section{Application: Essential Linux Commands for Beginners}

\subsection{Navigating the Filesystem}


\begin{alltt}

pwd                  \# Print Working Directory — where am I?
ls -la               \# List files (l = detailed, a = include hidden files)
cd /etc              \# Change to the /etc directory
cd \textasciitilde{}                 \# Go to your home directory
cat /etc/hostname    \# Display the contents of a file
less /var/log/syslog \# View a file one page at a time (q to quit)

\end{alltt}

\subsection{Managing Services with systemd}


\begin{alltt}

systemctl status matrix-synapse  \# Is the service running?
systemctl start matrix-synapse   \# Start it
systemctl stop matrix-synapse    \# Stop it
systemctl restart matrix-synapse \# Restart it
systemctl enable matrix-synapse  \# Start it automatically on boot
journalctl -u matrix-synapse -f  \# Watch the service's logs in real time
                                  \# (-f means "follow" — keeps updating)

\end{alltt}

\subsection{Security Essentials}


\begin{alltt}

\# Update all software (do this regularly!)
apt update \&\& apt upgrade -y

\# Check who is logged in
who

\# Check what ports are listening (what is exposed to the network)
ss -tlnp

\# Check firewall rules
nft list ruleset

\# View recent login attempts (look for brute-force attacks)
journalctl \_SYSTEMD\_UNIT=sshd.service \textbar{} grep "Failed password" \textbar{} tail -20

\end{alltt}

\subsection{Creating a Service Unit File (Example: a simple service)}


\begin{alltt}

\# /etc/systemd/system/myservice.service
[Unit]
Description=My Custom Service
After=network.target          \# Start after networking is up
Requires=postgresql.service   \# Start after PostgreSQL is ready

[Service]
Type=simple
User=myserviceuser            \# Run as a non-root user
WorkingDirectory=/opt/myservice
ExecStart=/opt/myservice/bin/start
Restart=on-failure            \# Restart if it crashes
RestartSec=5                  \# Wait 5 seconds before restarting

[Install]
WantedBy=multi-user.target    \# Start in normal (multi-user) mode

\# After creating/editing: reload systemd, then enable and start
systemctl daemon-reload
systemctl enable --now myservice

\end{alltt}


\noindent \textbf{Going Deeper: Linux Security Modules}


AppArmor (used on Ubuntu) and SELinux (used on RHEL\Slash{}Fedora) are Mandatory Access Control systems. Where normal Linux permissions say “this user can read this file,” AppArmor adds “this specific program can only access these specific files and network ports, regardless of what user it runs as.” Even if an attacker exploits a vulnerability in your Matrix server, AppArmor can prevent them from reading files outside the Matrix data directory. Enable and configure AppArmor profiles for all sensitive services.

\subsection{Chapter 3 Summary}


\begin{itemize}
\item\relax 
Linux is the only OS suitable for privacy-critical infrastructure because its code is fully auditable



\item\relax 
Every service should run as a non-root user with minimal permissions



\item\relax 
systemd manages services — use it to start services automatically and restart them on crash



\item\relax 
Namespaces and cgroups are the building blocks of containers



\item\relax 
Update software regularly; monitor logs for signs of intrusion




\end{itemize}
\chapter{Chapter 4: How Networks Work — From Cables to the Web}

\subsection{Learning Objectives}


\begin{itemize}
\item\relax 
Understand the OSI model and why layering matters for building resistance networks



\item\relax 
Know how IP addresses, DNS, and routing work — and how each can be attacked and defended



\item\relax 
Understand VLANs, network segmentation, and why they matter for security




\end{itemize}
\section{Theory: The OSI Model — Seven Layers of Networking}


All networking is built in layers. Each layer provides services to the layer above it and relies on the layer below it. This is one of the most important concepts in all of computing — understanding it lets you identify exactly where a problem or a block is occurring and what the appropriate counter-measure is.

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|X|X|}
\hline
\relax  Layer  &  Name  &  What it does  &  Real examples  &  How it can be attacked   \\
\hline
\relax  7  &  Application  &  The actual program the user interacts with  &  HTTP (web), SMTP (email), Matrix, XMPP  &  Block specific protocols or platforms   \\
\relax  6  &  Presentation  &  Encoding, encryption, compression  &  TLS\Slash{}SSL, JSON encoding  &  Break TLS, intercept before encryption   \\
\relax  5  &  Session  &  Opening, maintaining, closing connections  &  TLS sessions, TCP sessions  &  Session hijacking   \\
\relax  4  &  Transport  &  End-to-end delivery, error correction  &  TCP (reliable), UDP (fast)  &  Block specific ports   \\
\relax  3  &  Network  &  Logical addressing and routing  &  IPv4, IPv6, ICMP  &  Block IP ranges; BGP route withdrawal   \\
\relax  2  &  Data Link  &  Device-to-device delivery on the same network  &  Ethernet, Wi-Fi, MAC addresses  &  ARP spoofing, MAC flooding   \\
\relax  1  &  Physical  &  The actual medium: electricity, light, radio waves  &  Fiber optic, Ethernet cable, Wi-Fi radio waves  &  Cut cables, jam radio frequencies   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip


Think of sending a letter internationally. Layer 7 is the actual letter content. Layer 6 is the language it is written in. Layer 5 is the ongoing correspondence between you and the recipient. Layer 4 is the envelope. Layer 3 is the address on the envelope. Layer 2 is the postal truck carrying it within a city. Layer 1 is the road the truck drives on.


\textbf{Why this matters for resistance:} When a regime blocks access to a website (Layer 7), you can tunnel through that block at Layer 3 using a VPN. If they block VPNs at Layer 3, you can obfuscate your VPN traffic to look like normal Layer 7 HTTPS traffic. If they block all internet (Layer 3), you can communicate at Layer 1 with radio. Understanding the layers lets you always find a counter-move.

\section{Theory: IP Addresses — The Postal System of the Internet}


Every device on a network needs an address so that data can be routed to it. IP addresses are these addresses.


\textbf{IPv4} addresses look like \texttt{192.168.1.5} — four numbers from 0 to 255, separated by dots. There are about 4.3 billion possible IPv4 addresses. This seemed like a lot in the 1970s but is now running out.


\textbf{IPv6} addresses look like \texttt{2001:0db8:85a3:0000:0000:8a2e:0370:7334} — eight groups of four hexadecimal digits. There are 340 undecillion possible IPv6 addresses (that is 340 followed by 36 zeros). Every device on Earth could have billions of addresses.


\textbf{Private vs. public addresses:} Some IP address ranges are reserved for private networks (inside homes and offices). These include \texttt{10.0.0.0/8}, \texttt{172.16.0.0/12}, and \texttt{192.168.0.0/16}. They cannot be routed over the public internet — your router translates them to your single public IP address (this is called NAT — Network Address Translation).


\noindent \textbf{Beginner’s Corner: What is a subnet mask (\Slash{}24, \Slash{}16 etc.)?}


When you see \texttt{192.168.1.0/24}, the \texttt{/24} is a “prefix length” that tells you how many devices can be in this network. \texttt{/24} means the first 24 bits are the “network” part and the remaining 8 bits are for device addresses — giving you 254 usable addresses (192.168.1.1 to 192.168.1.254). \texttt{/16} gives you 65,534 addresses. \texttt{/8} gives you 16,777,214 addresses.

\section{Theory: DNS — The Phone Book}


When you type \texttt{matrix.example.com}, your computer does not know the IP address of that server. It asks a DNS (Domain Name System) resolver: “What is the IP address for matrix.example.com?” The resolver looks it up and returns the answer.


\textbf{How DNS censorship works:} The government orders ISPs to return wrong answers for certain domain names. Your computer asks “What is the IP of bbc.com?” and the ISP’s DNS resolver returns either the wrong address (redirecting you to a government page) or nothing at all (making the site unreachable).


\textbf{DNS counter-measures:}


\begin{itemize}
\item\relax 
\textbf{DNS-over-HTTPS (DoH)} — Send DNS queries over an encrypted HTTPS connection to a resolver outside the country (e.g., \texttt{1.1.1.1} or \texttt{9.9.9.9}). The ISP cannot intercept and manipulate the query.



\item\relax 
\textbf{Run your own DNS resolver} — Your network queries authoritative servers directly, bypassing ISP resolvers entirely.



\item\relax 
\textbf{Tor} — All DNS resolution happens at the Tor exit node, bypassing local DNS completely.




\end{itemize}
\section{Theory: Routing — How Data Finds Its Way}


When your computer sends data to a server in another country, that data passes through many “routers” — devices that look at the destination IP address and forward the packet toward its destination. Routers share information about which networks they can reach using routing protocols like BGP and OSPF.


\textbf{BGP (Border Gateway Protocol)} is used between organizations — between ISPs, between countries. It is how the global internet is “stitched together.” Each organization announces which IP ranges it owns, and other organizations learn those announcements and route traffic accordingly.


\textbf{Internet shutdown mechanism:} A government can order ISPs to withdraw their BGP announcements. Suddenly the rest of the world’s routers do not know how to reach IP addresses in that country. The country disappears from the internet. This is what happened in Egypt in 2011, Myanmar in 2021, and Sudan in 2023.

\section{Theory: VLANs — Dividing One Network into Many}


A VLAN (Virtual LAN) is a way of creating logically separate networks on the same physical switch infrastructure. A packet tagged with VLAN 10 cannot reach devices on VLAN 20 without explicitly crossing a router with rules permitting it.


For a resistance network, VLANs enforce compartmentalization:


\begin{alltt}

Physical switch (one device, multiple VLANs):

VLAN 10 (Management):  Admin laptops, Proxmox management UI
VLAN 20 (Services):    Matrix, XMPP, IPFS containers
VLAN 30 (Monitoring):  Prometheus, Grafana
VLAN 40 (External):    Servers that face the internet (with Tor)

Rules:
  VLAN 40 → VLAN 20: allowed (external services can reach internal)
  VLAN 20 → VLAN 10: DENIED (services cannot reach management)
  Any VLAN → VLAN 10: only from specific admin IPs

\end{alltt}

\section{Application: Setting Up DNS-over-HTTPS}

\subsection{Install and configure systemd-resolved with DoH (Ubuntu\Slash{}Debian)}


\begin{alltt}

\# Edit the resolved configuration
nano /etc/systemd/resolved.conf

\# Add these lines:
[Resolve]
DNS=1.1.1.1\#cloudflare-dns.com 9.9.9.9\#dns.quad9.net
DNSOverTLS=yes
DNSSEC=yes

\# Restart the resolver
systemctl restart systemd-resolved

\# Verify it is working (should show "DNSSEC: yes" and "DNS over TLS: yes")
resolvectl status

\end{alltt}

\subsection{Chapter 4 Summary}


\begin{itemize}
\item\relax 
The OSI model’s 7 layers each represent a different aspect of networking — and a different attack surface



\item\relax 
IP addresses are the routing addresses of the internet; understanding private vs. public addresses matters for network design



\item\relax 
DNS censorship is countered by DNS-over-HTTPS or running your own resolver



\item\relax 
BGP route withdrawal is how governments cause complete internet blackouts



\item\relax 
VLANs enforce compartmentalization between different security zones in your network




\end{itemize}
\chapter{Chapter 5: Virtualization — Running Many Computers Inside One}

\subsection{Learning Objectives}


\begin{itemize}
\item\relax 
Understand what a hypervisor is and how virtualization works



\item\relax 
Know the difference between a Virtual Machine (VM) and a Container



\item\relax 
Learn to install Proxmox VE and create your first VM




\end{itemize}
\section{Theory: What Virtualization Is}


A hypervisor is software that creates and manages “virtual machines” — simulated computers that run inside your real computer. Each virtual machine gets a portion of the real machine’s CPU, RAM, and storage. From the software’s point of view, it is running on its own dedicated computer.


\textbf{Type 1 hypervisors} (bare-metal) run directly on the hardware, with no underlying OS. They are faster and more secure. Proxmox VE is a Type 1 hypervisor.


\textbf{Type 2 hypervisors} run as an application inside an existing OS. VirtualBox and VMware Workstation are Type 2. They are convenient for personal desktops but slower and less suitable for servers.


Virtualization is like an apartment building. The building (physical server) has a finite amount of space (CPU, RAM, disk). The building manager (hypervisor) divides that space into apartments (virtual machines). Each apartment has its own lock, its own furniture, its own rules. A fire in apartment 3B does not spread to apartment 4A unless the building itself is compromised.

\section{Theory: VMs vs. Containers — Two Isolation Models}

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|}
\hline
\relax  Feature  &  Virtual Machine (VM)  &  Container   \\
\hline
\relax  What is isolated  &  Full operating system, kernel, hardware emulation  &  Filesystem, network, process namespace — shares the host kernel   \\
\relax  Isolation strength  &  Very strong — a compromised VM cannot easily escape to the host  &  Weaker — kernel vulnerabilities can allow container escape   \\
\relax  Startup time  &  30–120 seconds (full OS boot)  &  Less than 1 second   \\
\relax  Resource use  &  High — each VM has its own OS using RAM and disk  &  Low — many containers share the host OS   \\
\relax  Use for  &  Services requiring strong isolation (Tor relay, untrusted code)  &  Services you trust (Matrix, IPFS, Prometheus)   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip


\textbf{Rule of thumb:} Use VMs for anything internet-facing or security-sensitive (your Tor relay, your public-facing reverse proxy). Use containers for internal services that you control and trust.

\section{Theory: Proxmox VE}


Proxmox VE (Virtual Environment) is a free, open-source Type 1 hypervisor based on Debian Linux. It supports both QEMU\Slash{}KVM virtual machines and LXC containers. It includes a web-based management interface so you can manage everything from a browser.


For a resistance network, Proxmox is the foundation everything else runs on. It provides:


\begin{itemize}
\item\relax 
Isolation between services (VMs and containers)



\item\relax 
Snapshots — instant backup of any VM’s state



\item\relax 
Live migration — move a running VM from one physical host to another without downtime



\item\relax 
Cluster support — manage multiple physical machines as one pool of resources



\item\relax 
ZFS storage integration




\end{itemize}
\section{Application: Installing Proxmox VE}

\subsection{Step 1: Prepare installation media}


\begin{enumerate}[1.]
\item\relax 
Download the Proxmox VE ISO from \texttt{proxmox.com/en/downloads}



\item\relax 
Write it to a USB drive using Balena Etcher (Windows\Slash{}macOS) or \texttt{dd} (Linux)



\item\relax 
Boot your server from the USB drive (press F12, F2, or Del during startup to access boot menu)




\end{enumerate}
\subsection{Step 2: Install Proxmox}


\begin{enumerate}[1.]
\item\relax 
Select “Install Proxmox VE (Graphical)”



\item\relax 
Select your target disk — this will be erased. Choose a fast SSD if you have one.



\item\relax 
Set your country, timezone, keyboard layout



\item\relax 
Set a strong root password (save it somewhere safe)



\item\relax 
Set a static IP address for the management interface. Example: \texttt{192.168.1.10/24}



\item\relax 
After installation, remove the USB and reboot




\end{enumerate}
\subsection{Step 3: Access the management interface}


\begin{alltt}

\# From a browser on the same network:
https://192.168.1.10:8006

\# Log in with: root / [password you set]
\# Accept the self-signed certificate warning for now
\# (we will set up proper TLS later)

\# Remove the subscription warning (Proxmox is free without a subscription):
\# From the shell on the Proxmox host:
sed -i.bak "s/data.status !== 'Active'/false/g" \textbackslash{}
  /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js
systemctl restart pveproxy

\end{alltt}

\subsection{Step 4: Create your first VM (Ubuntu Server)}


\begin{enumerate}[1.]
\item\relax 
Upload the Ubuntu Server 24.04 ISO: Datacenter → local → ISO Images → Upload



\item\relax 
Click “Create VM” and follow the wizard: allocate 2 CPU cores, 4 GB RAM, 32 GB disk to start



\item\relax 
Start the VM and click the Console button to complete the Ubuntu installation




\end{enumerate}

\noindent \textbf{Hardware Recommendation}


A refurbished business desktop (Dell OptiPlex, HP EliteDesk, Lenovo ThinkCentre) with 16–32 GB RAM and a 500 GB SSD costs \$100–\$250 and runs Proxmox well. These machines are designed for 24\Slash{}7 operation, have good Linux driver support, and consume less power than consumer gaming PCs. Used enterprise servers (like a Dell R720) give you more power but are louder, larger, and consume more electricity.

\part{Part III — Private Networking}


Building encrypted tunnels and mesh networks that cannot be easily blocked

\chapter{Chapter 6: WireGuard — Building Your Encrypted Backbone}

\subsection{Learning Objectives}


\begin{itemize}
\item\relax 
Understand how WireGuard works from first principles



\item\relax 
Know the difference between a hub-and-spoke and a full-mesh VPN topology



\item\relax 
Set up a WireGuard full-mesh VPN between multiple nodes




\end{itemize}
\section{Theory: What a VPN Is and How WireGuard Works}


A VPN (Virtual Private Network) creates an encrypted “tunnel” between two or more computers. All traffic that passes through this tunnel is encrypted before it leaves your machine and decrypted only when it reaches the other end. To anyone watching the network in between — an ISP, a surveillance device, a government — the traffic appears as random, meaningless noise.


WireGuard is a modern VPN protocol that is:


\begin{itemize}
\item\relax 
\textbf{Simpler:} About 4,000 lines of code, compared to OpenVPN’s \textasciitilde{}100,000 lines. Fewer lines = smaller attack surface = easier to audit for security flaws.



\item\relax 
\textbf{Faster:} Uses state-of-the-art cryptography (ChaCha20 for encryption, Curve25519 for key exchange, BLAKE2 for hashing) that is extremely fast on modern hardware.



\item\relax 
\textbf{Stealthier:} WireGuard uses UDP and does not respond to connection attempts from unauthorized peers — the port appears “closed” or non-existent to outsiders, making the server harder to detect.




\end{itemize}
\section{Theory: Public and Private Keys}


WireGuard uses public-key cryptography for authentication. Every WireGuard peer has:


\begin{itemize}
\item\relax 
\textbf{A private key:} Generated once, kept secret, never shared with anyone. This is your identity — your proof that you are you. If someone gets your private key, they can impersonate you on the network.



\item\relax 
\textbf{A public key:} Mathematically derived from the private key. You share this with everyone you want to connect to. Knowing someone’s public key allows you to encrypt messages that only their private key can decrypt.




\end{itemize}

Your private key is like the key to your house. Your public key is like your home address. You share your address with anyone who wants to send you letters. But only you have the key that opens the lock on your mailbox. Even if someone knows your address perfectly, they cannot open your mailbox without your physical key.

\section{Theory: Hub-and-Spoke vs. Full Mesh}


\begin{alltt}

Hub-and-Spoke (centralized, fragile):   Full Mesh (decentralized, resilient):

        [HUB]                           [A]───[B]
       / \textbar{} \textbackslash{}                              \textbackslash{}   /
      /  \textbar{}  \textbackslash{}                              [C]
    [A] [B] [C]

Pros: Simple to configure               Pros: No single point of failure
Cons: HUB failure = network down        Cons: More configuration
      HUB can see all traffic                 (but Ansible handles this)

\end{alltt}


For a resistance network, always use full-mesh topology. Every node connects directly to every other node. Losing any one node does not interrupt connectivity between the survivors.

\section{Application: Setting Up WireGuard Full Mesh}

\subsection{Step 1: Install WireGuard on each node}


\begin{alltt}

\# On Debian/Ubuntu:
apt update \&\& apt install wireguard -y

\# Generate a key pair on each node:
wg genkey \textbar{} tee /etc/wireguard/private.key \textbar{} wg pubkey > /etc/wireguard/public.key

\# Set correct permissions (private key must not be readable by other users)
chmod 600 /etc/wireguard/private.key

\# Display your public key (share this with peers):
cat /etc/wireguard/public.key

\end{alltt}

\subsection{Step 2: Create the WireGuard configuration (Node A — 10.2.0.1)}


\begin{alltt}

\# /etc/wireguard/wg0.conf on Node A
[Interface]
Address = 10.2.0.1/24            \# This node's VPN IP address
ListenPort = 51820               \# UDP port to listen on
PrivateKey = [Node A private key]

\# Post-up/down: enable IP forwarding for routing
PostUp = sysctl -w net.ipv4.ip\_forward=1
PostDown = sysctl -w net.ipv4.ip\_forward=0

\# Peer: Node B
[Peer]
PublicKey = [Node B public key]
AllowedIPs = 10.2.0.2/32        \# Traffic to 10.2.0.2 goes through this peer
Endpoint = [Node B public IP]:51820   \# Where to find Node B on the internet
PersistentKeepalive = 25        \# Send a keepalive every 25 seconds (maintains NAT)

\# Peer: Node C
[Peer]
PublicKey = [Node C public key]
AllowedIPs = 10.2.0.3/32
Endpoint = [Node C public IP]:51820
PersistentKeepalive = 25

\end{alltt}

\subsection{Step 3: Enable and start WireGuard}


\begin{alltt}

\# Enable WireGuard to start on boot and start it now:
systemctl enable --now wg-quick@wg0

\# Verify it is running:
wg show

\# Test connectivity between nodes:
ping 10.2.0.2   \# From Node A, ping Node B's VPN address
ping 10.2.0.3   \# From Node A, ping Node C's VPN address

\end{alltt}

\subsection{Step 4: Open the firewall}


\begin{alltt}

\# Allow WireGuard UDP traffic through the firewall (nftables):
nft add rule inet filter input udp dport 51820 accept comment "WireGuard"

\# Save and persist:
nft list ruleset > /etc/nftables.conf
systemctl enable --now nftables

\end{alltt}


\noindent \textbf{If a peer is behind NAT (home router)}


If a node does not have a public IP address (it is behind a home router), it cannot easily receive incoming WireGuard connections. Solutions: (1) Forward UDP port 51820 on the router to the node. (2) Have the node behind NAT be the one that initiates the connection to a node with a public IP (the \texttt{PersistentKeepalive} setting handles this automatically). (3) Use a cheap VPS (\$5\Slash{}month) with a public IP as a relay.


\noindent \textbf{Going Deeper: Obfuscating WireGuard Traffic}


Some firewalls can detect and block WireGuard traffic by its UDP packet patterns. Tools like \textbf{Masque}, \textbf{AmneziaWG}, or wrapping WireGuard in a WebSocket tunnel using \textbf{wstunnel} make the traffic look like ordinary HTTPS to DPI systems. This adds complexity but is essential if WireGuard itself is being blocked.

\chapter{Chapter 7: Mesh Networks — When There Is No Infrastructure}

\subsection{Learning Objectives}


\begin{itemize}
\item\relax 
Understand how mesh networking works without any central infrastructure



\item\relax 
Learn about BATMAN-adv and how to build a local Wi-Fi mesh



\item\relax 
Know when and why to use a mesh network vs. a VPN




\end{itemize}
\section{Theory: What Makes a Mesh Network Different}


In a normal Wi-Fi network, all devices connect to a single router. The router provides internet access and routes traffic between devices. Remove the router, and the network dies.


In a \textbf{mesh network}, every device is both a client and a router. Data “hops” from device to device until it reaches its destination. There is no central router to remove. Every device that joins makes the network larger and more capable. Every device that leaves causes the network to route around the gap.


\begin{alltt}

Traditional Wi-Fi:          Mesh Network:
                            (each ● is a device that is
   [All devices]             both client AND router)
        \textbar{}
     [ROUTER]               ●──●──●
        \textbar{}                  /\textbar{}  \textbar{}  \textbar{}\textbackslash{}
   [Internet]             ● \textbar{}  \textbar{}  \textbar{} ●
                           \textbackslash{}\textbar{}  \textbar{}  \textbar{}/
   Remove router:           ●──●──●
   Network dies.
                           Remove any node:
                           Others route around it.

\end{alltt}

\section{Theory: BATMAN-adv — Better Approach To Mobile Adhoc Networking}


BATMAN-adv (B.A.T.M.A.N. advanced) is a mesh routing protocol that runs at Layer 2 (Data Link layer) of the OSI model. This means it works at the Ethernet\Slash{}Wi-Fi level, making it transparent to all Layer 3 protocols (TCP\Slash{}IP) and applications running above it.


How BATMAN-adv finds routes:


\begin{enumerate}[1.]
\item\relax 
Each node periodically broadcasts “Originator Messages” (OGMs) — small packets that say “I am here, this is my address.”



\item\relax 
Neighboring nodes receive these OGMs, add themselves, and rebroadcast them.



\item\relax 
By analyzing the OGMs it receives, each node learns the best path to every other node on the mesh.



\item\relax 
When a node disappears, its OGMs stop circulating. Other nodes automatically recalculate routes around it.




\end{enumerate}
\section{Application: Setting Up a BATMAN-adv Mesh}

\subsection{Step 1: Install BATMAN-adv}


\begin{alltt}

\# On each device that will be a mesh node:
apt update \&\& apt install batctl -y

\# Load the batman-adv kernel module:
modprobe batman-adv

\# Make it load on boot:
echo "batman-adv" >> /etc/modules

\end{alltt}

\subsection{Step 2: Configure the wireless interface for mesh mode}


\begin{alltt}

\# Bring down the wireless interface:
ip link set wlan0 down

\# Set it to mesh (ad-hoc or 802.11s) mode:
\# For 802.11s (Wi-Fi Mesh):
iw dev wlan0 set type mesh

\# Bring it back up:
ip link set wlan0 up

\# Join a mesh network (all nodes must use the same mesh ID):
iw dev wlan0 mesh join "resilience-mesh" freq 2412

\# Add the interface to batman-adv:
batctl if add wlan0

\# Bring up the batman-adv interface (bat0):
ip link set bat0 up
ip addr add 192.168.100.1/24 dev bat0  \# Unique address per node

\end{alltt}

\subsection{Step 3: Verify the mesh is working}


\begin{alltt}

\# See all nodes in the mesh and their link quality:
batctl n        \# Neighbors
batctl o        \# Originator table (all reachable nodes)

\# Test connectivity:
ping 192.168.100.2   \# Ping another mesh node

\# See routing path to a destination:
batctl traceroute 192.168.100.5

\end{alltt}


\noindent \textbf{Practical Scenario: City-Wide Mesh During Internet Shutdown}


During a complete internet shutdown, a group of 30 people across a city each run BATMAN-adv on a laptop or Raspberry Pi with a Wi-Fi adapter. As long as enough nodes are close enough to each other (ideally within 100–200 meters in urban environments), the mesh forms automatically. Users on the mesh can run a local Matrix server and communicate as if they have internet — without using internet at all.

\chapter{Chapter 8: Yggdrasil — A Self-Organizing Encrypted Internet}

\section{Theory: What Yggdrasil Is}


Yggdrasil is a proof-of-concept for a new type of internet — one that is end-to-end encrypted, fully decentralized, and self-organizing. Every node generates a public\Slash{}private key pair. Its IPv6 address on the Yggdrasil network is derived from its public key. This means:


\begin{itemize}
\item\relax 
Addresses are self-certifying — the address proves you are talking to the right node



\item\relax 
No central authority assigns addresses — you generate your own



\item\relax 
Routing is DHT-based — no central routing tables



\item\relax 
All traffic is encrypted end-to-end at the network layer




\end{itemize}
\section{Application: Installing and Connecting Yggdrasil}

\subsection{Install and configure Yggdrasil}


\begin{alltt}

\# Download and install (Debian/Ubuntu):
curl -o /tmp/yggdrasil.deb \textbackslash{}
  https://github.com/yggdrasil-network/yggdrasil-go/releases/latest/download/yggdrasil-linux-amd64.deb
dpkg -i /tmp/yggdrasil.deb

\# Generate a default config:
yggdrasil -genconf > /etc/yggdrasil/yggdrasil.conf

\# Edit the config — add peers (public peers available at:
\# https://github.com/yggdrasil-network/public-peers)
nano /etc/yggdrasil/yggdrasil.conf

\# Key section — add public peers:
\# Peers:
\#   - tls://[IP]:port   \# Public Yggdrasil peer

\# Enable and start:
systemctl enable --now yggdrasil

\# Check your Yggdrasil IPv6 address:
yggdrasilctl getSelf \textbar{} grep -i address

\# Ping another Yggdrasil node (use their Yggdrasil IPv6 address):
ping6 200:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx

\end{alltt}


\textbf{For your group’s private network:} Instead of using public peers, configure your group’s nodes as each other’s peers. Exchange peer addresses out-of-band (in person or over an already-trusted channel). Your group then has a fully private, encrypted network using Yggdrasil addresses.

\part{Part IV — Decentralized Architecture}


The theory behind why distributed systems are resilient — from P2P to consensus

\chapter{Chapter 9: Peer-to-Peer Networking — Theory and Practice}

\section{Theory: The Architecture of P2P Systems}


In a peer-to-peer (P2P) network, every participant is simultaneously a client (consuming resources) and a server (providing resources). There is no privileged central node. Every peer is equal in architecture, even if some are more “connected” than others in practice.


P2P systems can be categorized by how structured their routing is:

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|X|}
\hline
\relax  Type  &  How It Routes  &  Example  &  Tradeoff   \\
\hline
\relax  \textbf{Unstructured P2P}  &  Flood queries to all neighbors; search spreads like a rumor  &  Early Gnutella, BitTorrent search  &  Simple but doesn’t scale — too many messages for large networks   \\
\relax  \textbf{Structured P2P (DHT)}  &  Mathematical routing table (DHT); queries go directly to responsible nodes  &  IPFS, BitTorrent DHT, Hyphanet  &  Efficient and scalable; slightly more complex   \\
\relax  \textbf{Hybrid P2P}  &  Some centralized components (e.g. a tracker) for bootstrapping; rest is P2P  &  BitTorrent with trackers, Tor with directory servers  &  More reliable initially; central components are potential targets   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip

\section{Theory: Overlay Networks in Detail}


An overlay network is a virtual network layered on top of an existing network. The overlay defines its own addressing, routing, and topology — independent of how the underlying network routes packets.


\begin{alltt}

Physical Internet Topology:         Overlay Network Topology:
(how packets actually travel)       (virtual connections between peers)

[A]──[router1]──[B]                 [A]══════════════[B]
  \textbackslash{}               \textbackslash{}                  ║                 ║
[router2]──[C]──[router3]           ║       [C]       ║
                    \textbackslash{}                ╚══════╗   ╔═════╝
                   [D]                     [D]══╝

Physical path A→B goes through router1.   Overlay: A has a direct encrypted
Physical path A→D goes through many hops. tunnel to B, C, and D. The overlay
                                          can route differently than the
                                          physical network.

\end{alltt}


This is exactly what Tor, I2P, and Yggdrasil do — they create a virtual topology that is independent of, and often contrary to, the physical internet topology. This is why they can defeat routing-based blocks: your traffic might physically travel through the blocking ISP, but it is encrypted and does not look like the traffic being blocked.

\section{Theory: Distributed Service Discovery Without a Center}


How do peers find each other in a P2P network without a central directory? There are several mechanisms:


\textbf{Bootstrap nodes:} A small, well-known set of initial entry points. You contact a bootstrap node to get your initial list of peers. After that, discovery is fully decentralized. Bootstrap nodes are not essential for ongoing operation — they only help you join for the first time.


\textbf{Gossip protocols:} Each node periodically tells a random selection of its neighbors what it knows — peers it has seen, services it has heard about. Information “gossips” through the network. Within a few rounds of gossip, every node knows about every service. This is how Matrix federation finds other servers.


\textbf{mDNS (Multicast DNS):} Devices on the same local network announce services by broadcasting to a multicast address. Anyone on the network who is interested listens. Used by IPFS to find local peers automatically.


\noindent \textbf{Practical Advice: Bootstrapping a Private Network}


For a private group network, distribute a list of bootstrap addresses out-of-band — printed on paper, shared in person. Include at least 3 bootstrap addresses in case some nodes are down. Once a new node connects to even one bootstrap peer, it discovers the rest automatically through DHT or gossip. Update the bootstrap list whenever your infrastructure changes significantly.

\chapter{Chapter 10: Distributed Hash Tables and Kademlia}

\section{Theory: What a Hash Is}


A \textbf{cryptographic hash function} takes any input (a file, a string, a document) and produces a fixed-length output (the “hash” or “digest”) with two critical properties:


\begin{enumerate}[1.]
\item\relax 
\textbf{Deterministic:} The same input always produces the same output



\item\relax 
\textbf{One-way and avalanche:} You cannot reverse the hash to find the input; changing even one character of the input completely changes the output




\end{enumerate}

Example (SHA-256 hash):


\begin{alltt}

Input: "Hello, world!"
Hash:  315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3

Input: "Hello, world?" (only one character changed — ! to ?)
Hash:  61c9b1a5d07b9e4acea9a7b3c8a34f15e2c6e4d9f7a2b1c3e5d7f9a1b3c5d7f9
       (completely different output)

\end{alltt}

\section{Theory: How a Distributed Hash Table Works}


A Distributed Hash Table (DHT) is a decentralized key-value store. You can think of it as a dictionary — a lookup table where you provide a key and get back a value — except that this dictionary is spread across millions of nodes with no central server.


The core idea:


\begin{enumerate}[1.]
\item\relax 
Both nodes and stored items are assigned IDs in the same ID space (e.g., 160-bit numbers)



\item\relax 
Each node is responsible for storing items whose IDs are “close” to its own ID



\item\relax 
To find an item, you route a query toward nodes with IDs closest to the item’s ID



\item\relax 
The routing converges in O(log N) hops — logarithmic scaling means even huge networks require very few hops




\end{enumerate}
\section{Theory: Kademlia in Detail}


Kademlia is the DHT algorithm used by IPFS, the BitTorrent DHT, and many other systems. Its key innovation is using XOR (exclusive-or) as its distance metric.


\textbf{Why XOR?} XOR has a useful mathematical property: the XOR distance between two IDs is symmetric (distance A→B = distance B→A), and there is exactly one “closest point” between any two IDs. This makes routing tables unambiguous and efficient.


\textbf{k-buckets:} Each node maintains a routing table organized as “k-buckets” — lists of contacts at different XOR distances from itself. Nodes that are “XOR-close” go in one bucket; nodes that are “XOR-far” go in another. Each bucket holds at most k contacts (usually k=20).


\textbf{Self-healing:} Kademlia nodes regularly check that their k-bucket contacts are still alive (by pinging them). Dead contacts are replaced with live ones. When a node joins after being offline, it re-announces itself to its responsible section of the DHT. The network heals itself without any administrator action.


\begin{alltt}

Kademlia lookup example (finding node or content with ID=42):

Your node ID: 5 (binary: 00000101)
Target ID: 42  (binary: 00101010)
XOR distance: 00101111 = 47

Step 1: Check your k-bucket for IDs with XOR distance \textasciitilde{}47
        Closest known node: ID=30 (XOR 5⊕30=27, closer to 42 than we are)

Step 2: Ask node ID=30 "Who do you know closest to ID=42?"
        It replies: ID=38 (XOR 30⊕38=8, even closer)

Step 3: Ask node ID=38 "Who do you know closest to ID=42?"
        It replies: ID=41 (XOR 38⊕41=11, very close)

Step 4: Ask node ID=41 "Who do you know closest to ID=42?"
        It replies: ID=43 (stores data for ID=42)

Step 5: Ask node ID=43 for the content. Retrieved!

Total: 4 hops to find one item in a network of any size.
In a network of 1 million nodes, this takes \textasciitilde{}20 hops.

\end{alltt}

\section{Application: IPFS and DHT in Practice}

\subsection{Using IPFS (which uses Kademlia DHT internally)}


\begin{alltt}

\# Install IPFS:
wget https://dist.ipfs.tech/kubo/v0.28.0/kubo\_v0.28.0\_linux-amd64.tar.gz
tar -xzf kubo\_v0.28.0\_linux-amd64.tar.gz
cd kubo \&\& ./install.sh

\# Initialize a node:
ipfs init

\# Start the IPFS daemon:
ipfs daemon \&

\# Add a file to IPFS (returns the content ID — the hash):
ipfs add important-document.pdf
\# Output: added QmXxxxx... important-document.pdf

\# Retrieve the same file from any other IPFS node:
ipfs get QmXxxxx...

\# Pin a file (keep a permanent local copy, don't garbage-collect it):
ipfs pin add QmXxxxx...

\# See your peer connections (these are all DHT neighbors):
ipfs swarm peers \textbar{} head -20

\end{alltt}

\chapter{Chapter 11: Content-Addressed Storage — Files That Cannot Be Deleted}

\section{Theory: Location-Addressed vs. Content-Addressed}


The traditional web uses \textbf{location-addressed storage}: you find a file by where it is (its URL). Change the server, move the file, or shut down the hosting provider, and the file is gone — even if a million copies exist elsewhere.


\textbf{Content-addressed storage} names files by what they contain (their cryptographic hash). The content hash is a permanent, unforgeable identifier derived from the file itself. This has profound implications:

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|}
\hline
\relax  Property  &  Explanation  &  Resistance Application   \\
\hline
\relax  \textbf{Immutability}  &  The hash is a permanent name — you cannot “update” a file without creating a new hash  &  Published documents cannot be secretly altered; share the hash, and anyone can verify the document is unchanged   \\
\relax  \textbf{Location independence}  &  The same file can be served from any node that has it — the hash doesn’t care where it comes from  &  No URL to block; as long as one copy exists anywhere, the file is retrievable   \\
\relax  \textbf{Deduplication}  &  Identical files always have the same hash — stored only once even if “uploaded” many times  &  Efficient spreading of documents across many nodes without wasted storage   \\
\relax  \textbf{Cryptographic verification}  &  After downloading, hash the file — if it matches the expected hash, the content is authentic  &  Detect tampering even if the transmission channel is compromised   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip

\section{Theory: Merkle Trees — How Git and IPFS Structure Data}


A Merkle tree is a tree structure where every node’s label is the hash of its children. The root of the tree (the “Merkle root”) summarizes the hash of all data beneath it. Changing any piece of data changes its hash, which changes its parent’s hash, which propagates all the way to the root.


This is how IPFS represents directories: a directory is a Merkle tree node containing the hashes of all its files and subdirectories. You only need the root hash to verify the integrity of the entire directory tree.


This is also how Git works: every commit contains the hash of the file tree plus the hash of the previous commit. You cannot alter any past commit without changing all subsequent commits — tampering is immediately detectable.


A Merkle tree is like a family tree where every person’s name is derived from their children’s names. If you change a grandchild’s name, it changes the child’s name, which changes the grandparent’s name. Anyone who knows the grandparent’s “name” can instantly detect that something has changed downstream.

\section{Application: Publishing a Document on IPFS}

\subsection{Publishing and sharing content that cannot be censored}


\begin{alltt}

\# Add a document to IPFS:
ipfs add -r /path/to/document-or-folder/

\# The output gives you the CID (Content Identifier — the hash):
\# added QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG document.pdf

\# Share the CID with your group.
\# Anyone who runs IPFS can now retrieve it:
ipfs get QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG

\# To ensure the document is always available, pin it on multiple nodes:
\# (Run this on each node in your network)
ipfs pin add QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG

\# Make IPFS start on boot:
\# Create a systemd service for the IPFS daemon
cat > /etc/systemd/system/ipfs.service << 'EOF'
[Unit]
Description=IPFS Daemon
After=network.target

[Service]
Type=simple
User=ipfs
ExecStart=/usr/local/bin/ipfs daemon
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

useradd -r -s /bin/false ipfs
mkdir -p /home/ipfs \&\& chown ipfs:ipfs /home/ipfs
systemctl enable --now ipfs

\end{alltt}

\chapter{Chapter 12: Federation, Distributed Identity, and Consensus}

\section{Theory: Federation — The Email Model for Everything}


Email is the oldest and most successful federated system. You have a Gmail address; your friend has a Protonmail address. You can email each other. Why? Because both Gmail and Protonmail implement the SMTP standard. Neither company controls the whole email network.


Matrix and XMPP apply this model to instant messaging. Anyone can run a server, and servers interoperate automatically. This is fundamentally different from WhatsApp or Telegram, where a single company controls all servers and can:


\begin{itemize}
\item\relax 
Read all messages (even if they claim not to)



\item\relax 
Delete accounts



\item\relax 
Block accounts from specific regions



\item\relax 
Hand over user data to governments



\item\relax 
Shut down the service entirely




\end{itemize}
\section{Theory: Distributed Identity — Who Are You Without a Central Authority?}


In centralized systems, identity is delegated to a trusted authority. Google says “this is Alice’s account.” If Google is pressured, Alice’s identity can be revoked. In decentralized systems, identity is cryptographic.


\textbf{How it works:} Alice generates a key pair (private key + public key). Her public key becomes her identity — it is her name in the decentralized network. When she sends a message, she signs it with her private key. Anyone can verify the signature using her public key, confirming the message came from Alice (the holder of the matching private key).


No central authority needed. No government can revoke her key. The only way to “take away” her identity is to obtain her private key — which only she possesses.


\noindent \textbf{The Key Exchange Problem}


The hardest problem with cryptographic identity: how do you initially get and verify someone’s public key? If an adversary can intercept the exchange and substitute their own public key, they can impersonate the legitimate party (a “man-in-the-middle” attack). The solution: verify key fingerprints out-of-band — in person, or over a channel you already trust independently. Matrix’s “cross-signing” feature handles this with QR codes.

\section{Theory: Eventual Consistency vs. Strong Consistency}


When data is replicated across multiple nodes, those nodes may temporarily disagree about the current state. There are two approaches:


\textbf{Eventual consistency:} Nodes may be temporarily out of sync, but the system guarantees that given enough time and no new updates, all nodes will converge to the same state. Good enough for most communication systems (messages delivered in seconds rather than immediately).


\textbf{Strong consistency:} All reads see the most recent write. No node ever sees stale data. Requires coordination between nodes for every write — more complex and slower. Required for financial ledgers, voting systems.


For resistance networks, eventual consistency is almost always sufficient and much simpler to implement.

\section{Theory: Consensus — How Distributed Systems Make Decisions}


When multiple nodes store data and any node can receive writes, they need a way to agree on which write “wins” when there are conflicts. This is the consensus problem.


\textbf{The Raft algorithm} (used by many modern distributed systems):


\begin{enumerate}[1.]
\item\relax 
Nodes elect a \textbf{leader} by vote — the node that gets votes from a majority of nodes becomes leader



\item\relax 
All writes go to the leader first



\item\relax 
The leader replicates the write to followers and waits for a majority to acknowledge



\item\relax 
Only after a majority acknowledges does the leader commit the write



\item\relax 
If the leader dies, remaining nodes automatically elect a new leader




\end{enumerate}

\textbf{Why “majority” matters:} With 3 nodes, a majority is 2. You can lose 1 node and still make progress. With 5 nodes, a majority is 3 — you can lose 2 nodes. With 2 nodes, a majority requires both — losing one node stops all writes. Always use an odd number of nodes.

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|X|}
\hline
\relax  Cluster Size  &  Quorum (majority)  &  Can lose N nodes  &  Recommendation   \\
\hline
\relax  1  &  1  &  0  &  Never use for critical data   \\
\relax  2  &  2  &  0  &  Worse than useless — same as 1 but costs more   \\
\relax  3  &  2  &  1  &  Minimum for high availability   \\
\relax  5  &  3  &  2  &  Good for higher resilience   \\
\relax  7  &  4  &  3  &  For maximum resilience across geographic locations   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip

\part{Part V — Anonymous \& Censorship-Resistant Communications}


The actual tools for private, uncensorable communication

\chapter{Chapter 13: Tor — Anonymity Through the Crowd}

\section{Theory: How Tor Works}


Tor (The Onion Router) anonymizes internet traffic by routing it through a series of relays, with each relay knowing only the previous and next hop — never both the origin and destination simultaneously. This is called “onion routing” because messages are wrapped in multiple layers of encryption, like the layers of an onion.


\begin{alltt}

Without Tor:
[You]───────────────────────────[Website]
     ← ISP sees: You visited Website →

With Tor:
[You]→[Guard relay]→[Middle relay]→[Exit relay]→[Website]
  ↑         ↑              ↑              ↑
  Knows    Knows         Knows          Knows
  you're  Guard+Middle  Middle+Exit    Exit→Web
  online   but not you   but not you   but not you

No single relay knows both who you are AND where you're going.

\end{alltt}


\textbf{The three hop circuit:} Every Tor connection uses at least 3 relays: a Guard (entry), a Middle, and an Exit. Your client negotiates encryption with each relay separately. Messages are triple-encrypted before leaving your machine. Each relay decrypts one layer (like peeling an onion) and forwards the remainder to the next relay.

\section{Theory: Onion Services — Hidden Servers}


An “onion service” (formerly called a “hidden service”) is a server that is only accessible through Tor. Its real IP address is never revealed. It has an address like \texttt{duskgytldkxiuqc6.onion} — a hash of the service’s public key.


How onion services work:


\begin{enumerate}[1.]
\item\relax 
The server generates a key pair and derives its .onion address from the public key



\item\relax 
The server selects “introduction points” (Tor relays) and announces them to the Tor DHT



\item\relax 
A client that wants to connect selects a “rendezvous point” relay and tells the server (via an introduction point)



\item\relax 
The server connects to the rendezvous point; now the client and server have a circuit through the rendezvous — neither knows the other’s IP address




\end{enumerate}

This means: the server’s location is hidden from the client, the client’s location is hidden from the server, and neither the ISP nor any network observer can determine where either party is.

\section{Application: Running Your Matrix Server as a Tor Onion Service}

\subsection{Step 1: Install Tor}


\begin{alltt}

apt update \&\& apt install tor -y

\end{alltt}

\subsection{Step 2: Configure a hidden service}


\begin{alltt}

\# Edit /etc/tor/torrc and add:
HiddenServiceDir /var/lib/tor/matrix-onion/
HiddenServicePort 8448 127.0.0.1:8448   \# Matrix federation port
HiddenServicePort 443 127.0.0.1:8448    \# HTTPS port

\# Restart Tor:
systemctl restart tor

\# Get your .onion address (generated automatically):
cat /var/lib/tor/matrix-onion/hostname
\# Output: something like duskgytldkxiuqc6ztxy.onion

\end{alltt}

\subsection{Step 3: Configure Matrix to use the onion address}


\begin{alltt}

\# In your Matrix (Synapse) homeserver.yaml:
server\_name: "duskgytldkxiuqc6ztxy.onion"
public\_baseurl: "http://duskgytldkxiuqc6ztxy.onion"

\end{alltt}


\noindent \textbf{Tor Bridges: When Tor Itself is Blocked}


Some countries block access to Tor’s public relays. Tor bridges are unlisted relays that are not published in Tor’s directory. Get bridges from \texttt{bridges.torproject.org} or by emailing \texttt{bridges@torproject.org}. For the most difficult blocking environments, use Pluggable Transports like \textbf{obfs4} (disguises Tor traffic as random data) or \textbf{meek} (disguises it as HTTPS traffic to major cloud providers).

\chapter{Chapter 14: I2P — The Hidden Services Network}

\section{Theory: I2P vs. Tor}


I2P (Invisible Internet Project) and Tor are both anonymity overlay networks, but they are designed for different use cases:

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|}
\hline
\relax  Feature  &  Tor  &  I2P   \\
\hline
\relax  Primary use  &  Accessing the regular internet anonymously (outbound proxy)  &  Hosting services within the I2P network (internal services)   \\
\relax  Architecture  &  Centralized directory servers; sequential circuit  &  Fully distributed; “garlic routing” bundles multiple messages   \\
\relax  Exit to regular internet  &  Yes, via exit nodes  &  Limited (outproxies exist but not recommended)   \\
\relax  Hidden services  &  .onion addresses  &  .i2p addresses (“eepsites”)   \\
\relax  DHT  &  No — uses centralized directory  &  Yes — fully distributed   \\
\relax  Best for  &  Browsing the web, accessing external sites anonymously  &  Hosting internal services (chat, file sharing, forums) with strong anonymity   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip

\section{Application: Running an I2P Service}

\subsection{Install I2P (Java version)}


\begin{alltt}

\# Add the I2P repository (Debian/Ubuntu):
apt-add-repository ppa:i2p-maintainers/i2p
apt update \&\& apt install i2p -y

\# Start I2P:
systemctl enable --now i2p

\# Access the I2P router console from a browser:
\# http://127.0.0.1:7657

\# The console shows your tunnel build status, bandwidth, and
\# lets you create new "eepsite" (hidden service) tunnels.
\# Allow 10-20 minutes for tunnels to build and the network to integrate.

\end{alltt}

\chapter{Chapter 15: Matrix — Federated Encrypted Messaging}

\subsection{Learning Objectives}


\begin{itemize}
\item\relax 
Understand how Matrix federation works and why it is superior to centralized chat



\item\relax 
Install and configure a Matrix homeserver (Synapse)



\item\relax 
Set up end-to-end encryption and verify device keys




\end{itemize}
\section{Theory: The Matrix Protocol Architecture}


Matrix is an open standard for real-time communication. The architecture has three parts:


\begin{itemize}
\item\relax 
\textbf{Homeservers:} Servers that store messages and user accounts for their users. Anyone can run one. Synapse is the reference implementation.



\item\relax 
\textbf{Clients:} Apps that users interact with. Element is the most common. Clients connect to their homeserver.



\item\relax 
\textbf{Rooms:} The fundamental unit of communication. A room can have participants from any homeserver. Each homeserver that has a member in a room stores a replicated copy of all messages in that room.




\end{itemize}

\textbf{End-to-end encryption (E2EE):} Matrix supports E2EE via the Megolm protocol (based on Double Ratchet, the same protocol used by Signal). When E2EE is enabled in a room, messages are encrypted by the sender’s device before being sent to the homeserver. The homeserver stores and forwards only ciphertext — it cannot read messages even if subpoenaed.

\section{Application: Installing Matrix Synapse}

\subsection{Step 1: Install Synapse}


\begin{alltt}

\# Add the Matrix repository:
apt install -y lsb-release wget apt-transport-https
wget -O /usr/share/keyrings/matrix-org-archive-keyring.gpg \textbackslash{}
  https://packages.matrix.org/debian/matrix-org-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/matrix-org-archive-keyring.gpg] \textbackslash{}
  https://packages.matrix.org/debian/ \$(lsb\_release -cs) main" \textbackslash{}
  > /etc/apt/sources.list.d/matrix-org.list
apt update \&\& apt install matrix-synapse-py3 -y

\end{alltt}

\subsection{Step 2: Configure Synapse}


\begin{alltt}

\# Generate the initial config (replace with your server name):
python3 -m synapse.app.homeserver \textbackslash{}
  --server-name matrix.yourdomain.onion \textbackslash{}
  --config-path /etc/matrix-synapse/homeserver.yaml \textbackslash{}
  --generate-config \textbackslash{}
  --report-stats=no

\# Key settings to review in homeserver.yaml:
\# server\_name: "matrix.yourdomain.onion"   ← your server's identity
\# enable\_registration: false                ← disable open registration
\# registration\_shared\_secret: "CHANGE\_ME"  ← for adding users via admin
\# database:                                 ← configure PostgreSQL here

\# Set up PostgreSQL as the database backend (much better than SQLite):
apt install postgresql -y
sudo -u postgres psql -c "CREATE USER synapse WITH PASSWORD 'STRONGPASS';"
sudo -u postgres psql -c "CREATE DATABASE synapse OWNER synapse \textbackslash{}
  ENCODING 'UTF8' LC\_COLLATE='C' LC\_CTYPE='C' template=template0;"

\end{alltt}

\subsection{Step 3: Create your first user}


\begin{alltt}

\# Start Synapse:
systemctl enable --now matrix-synapse

\# Create an admin user (run as root, uses registration\_shared\_secret):
register\_new\_matrix\_user -c /etc/matrix-synapse/homeserver.yaml \textbackslash{}
  -u admin -p 'STRONGPASSWORD' -a http://localhost:8008

\# Check Synapse logs:
journalctl -u matrix-synapse -f

\end{alltt}

\subsection{Step 4: Enable end-to-end encryption verification}


\begin{alltt}

\# In Element (the client app):
\# Settings → Security → Cross-signing
\# Click "Set up" and follow the prompts
\# This creates a master key that certifies all your device keys

\# Share your room and enable encryption:
\# In any room → Settings → Security \& Privacy → Encrypted → Enable

\# Verify another user's identity:
\# Click their name → Verify
\# Use QR code scan (in-person) or emoji comparison (remote)

\end{alltt}


\noindent \textbf{Going Deeper: Matrix Replication}


Every homeserver that has at least one user in a room stores a full replicated copy of all messages in that room. This means if your homeserver goes down, messages are still stored on other homeservers. This built-in replication is a major resilience advantage. For maximum resilience, ensure your users are in rooms with members from multiple homeservers — the room’s history is then replicated across all of them.

\chapter{Chapter 16: XMPP — The Battle-Tested Protocol}

\section{Theory: What XMPP Is}


XMPP (Extensible Messaging and Presence Protocol) was designed in 1999 as an open, federated alternative to proprietary instant messaging. It has been used by activists, journalists, and privacy-conscious users for decades and is widely considered one of the most battle-tested messaging protocols available.


XMPP’s key strengths for resistance:


\begin{itemize}
\item\relax 
\textbf{OMEMO encryption:} An extension providing double-ratchet end-to-end encryption (the same type Signal uses)



\item\relax 
\textbf{Lightweight:} Runs on very old or low-power hardware



\item\relax 
\textbf{Mature:} Decades of security research and real-world deployment



\item\relax 
\textbf{Works over Tor:} Connect your XMPP client to your server via Tor for anonymity




\end{itemize}
\section{Application: Installing Prosody XMPP Server}

\subsection{Install and configure Prosody}


\begin{alltt}

\# Install Prosody:
apt install prosody -y

\# Edit /etc/prosody/prosody.cfg.lua:
VirtualHost "chat.yourdomain.onion"

\# Enable modules:
modules\_enabled = \{
  "roster"; "saslauth"; "tls"; "dialback";
  "disco"; "carbons"; "pep"; "private";
  "blocklist"; "vcard4"; "vcard-legacy";
  "version"; "uptime"; "time"; "ping";
  "register"; "admin\_adhoc";
  "http\_upload"; -- for file sharing
  "smacks"; -- for mobile reconnection
\}

\# Disable open registration (invite-only network):
allow\_registration = false

\# Enable HTTPS for web-based file upload:
https\_ssl = \{ certificate = "/etc/ssl/..."; key = "/etc/ssl/..."; \}

\# Start Prosody:
systemctl enable --now prosody

\# Add a user:
prosodyctl adduser alice@chat.yourdomain.onion

\end{alltt}

\chapter{Chapter 17: IPFS — The Censorship-Resistant File System}


(See Chapter 11 for theory. This chapter focuses on operational use.)

\section{Application: Running a Private IPFS Cluster}


A public IPFS node connects to the global IPFS network. For a private network, you can configure IPFS to connect only to trusted peers.

\subsection{Configure a private IPFS network}


\begin{alltt}

\# Generate a shared swarm key (all private nodes must have this exact key):
go install github.com/Kubuxu/go-ipfs-swarm-key-gen/ipfs-swarm-key-gen@latest
ipfs-swarm-key-gen > /var/ipfs/.ipfs/swarm.key
\# Copy /var/ipfs/.ipfs/swarm.key to every node in your private network

\# Remove the default public bootstrap nodes:
ipfs bootstrap rm all

\# Add your own nodes as bootstrap peers:
ipfs bootstrap add /ip4/10.2.0.1/tcp/4001/p2p/[PeerID of node 1]
ipfs bootstrap add /ip4/10.2.0.2/tcp/4001/p2p/[PeerID of node 2]

\# Get a node's PeerID:
ipfs id \textbar{} grep '"ID"'

\# Verify only your peers are connected:
ipfs swarm peers
\# Should only show your private nodes

\end{alltt}

\chapter{Chapter 18: Hyphanet — Publishing Without a Trace}

\section{Theory: How Hyphanet Achieves Censorship Resistance}


Hyphanet (formerly Freenet) achieves censorship resistance through two mechanisms:


\textbf{1. Plausible deniability through fragment distribution:} Files are split into small encrypted chunks that are distributed across participating nodes. No single node stores a complete file. No single node knows what data it is storing (the chunks are encrypted). A node cannot be held legally responsible for content it cannot read and does not know it has.


\textbf{2. Opennet vs. Darknet mode:} In opennet mode, Hyphanet connects to any available node. In darknet mode, it connects only to a list of nodes you explicitly trust. Darknet mode is far more resistant to infiltration and monitoring — an adversary would need to personally befriend all of a node’s trusted contacts to analyze its network position.

\section{Application: Installing Hyphanet}

\subsection{Install Hyphanet (requires Java)}


\begin{alltt}

\# Install Java:
apt install default-jre -y

\# Download the Hyphanet installer:
wget https://github.com/hyphanet/fred/releases/download/build01497/new\_installer\_offline\_1497.jar

\# Run the installer:
java -jar new\_installer\_offline\_1497.jar

\# Hyphanet runs a local web interface at:
\# http://127.0.0.1:8888

\# First run: the wizard guides you through:
\# 1. Data store size (how much disk space to contribute)
\# 2. Connectivity (opennet or darknet)
\# 3. If darknet: add trusted friend nodes by exchanging node references

\# Publishing a document (Freesites):
\# Use the Freesite Inserter in the web interface
\# After insertion, you receive a permanent URI (key) to share

\end{alltt}

\chapter{Chapter 19: Voice — Asterisk and Encrypted Calls}

\section{Theory: How VoIP Works}


VoIP (Voice over IP) converts voice audio into digital data packets that travel over a network. The SIP (Session Initiation Protocol) is used to set up and tear down calls. RTP (Real-time Transport Protocol) carries the actual audio.


Asterisk is a free, open-source PBX (Private Branch Exchange) — a phone system. It can route calls between extensions, connect to the public telephone network via SIP trunks, manage voicemail, and run conference bridges.


For a resistance network, Asterisk running on your private infrastructure means:


\begin{itemize}
\item\relax 
Voice calls that do not pass through any telecommunications company



\item\relax 
No call records at any telco (they cannot be subpoenaed)



\item\relax 
SRTP (Secure RTP) for encrypted audio



\item\relax 
Accessible over your WireGuard VPN or as a Tor onion service




\end{itemize}
\section{Application: Installing Asterisk}

\subsection{Basic Asterisk installation and extension setup}


\begin{alltt}

\# Install Asterisk:
apt install asterisk -y

\# Configure extensions (/etc/asterisk/sip.conf):
[general]
context=default
udpbindaddr=0.0.0.0:5060
transport=tls    ; Use TLS for signaling
tlscertfile=/etc/ssl/certs/asterisk.crt
tlsprivatekey=/etc/ssl/private/asterisk.key
tlscafile=/etc/ssl/certs/ca.crt

; Extension 100 (Alice):
[alice]
type=friend
secret=STRONGPASSWORD
host=dynamic     ; Alice's IP is dynamic
context=default
encrypt=yes      ; Require SRTP encryption
qualify=yes      ; Ping regularly to detect availability

; Extension 101 (Bob):
[bob]
type=friend
secret=STRONGPASSWORD2
host=dynamic
context=default
encrypt=yes
qualify=yes

\# Configure dialplan (/etc/asterisk/extensions.conf):
[default]
; Dial extension 100:
exten => 100,1,Dial(SIP/alice,30)  ; Ring for 30 seconds
; Dial extension 101:
exten => 101,1,Dial(SIP/bob,30)

\# Restart Asterisk:
systemctl enable --now asterisk

\# Clients: Install "Linphone" or "Zoiper" on a phone/laptop
\# Connect to your Asterisk server's IP over the VPN with SIP+TLS

\end{alltt}

\part{Part VI — Storage, Databases \& Infrastructure}


Storing data reliably so nothing is ever lost

\chapter{Chapter 20: Storage — ZFS, Ceph, and Backups}

\section{Theory: What ZFS Does That Normal Filesystems Don’t}


Traditional filesystems (ext4, NTFS, FAT32) are vulnerable to “silent corruption” — data on disk is silently changed by a failing drive, cosmic ray, or software bug, and the filesystem reports the corrupted data as if it were correct. ZFS prevents this with:


\begin{itemize}
\item\relax 
\textbf{Checksums on all data and metadata:} Every block on disk has a checksum. On every read, ZFS verifies the checksum. If it fails, ZFS knows the data is corrupt.



\item\relax 
\textbf{Copy-on-write:} ZFS never overwrites existing data. When you update a file, ZFS writes the new data to a new location, then atomically updates the pointer. If the system crashes mid-write, the old data is still intact.



\item\relax 
\textbf{Snapshots:} Because of copy-on-write, snapshots are instant (zero copy, zero space initially) and cheap. A snapshot captures the exact state of a filesystem at a moment in time. Snapshots only use space as the original data changes.



\item\relax 
\textbf{RAID-Z:} ZFS has built-in redundancy levels equivalent to RAID 5\Slash{}6\Slash{}7 but without the “RAID-5 write hole” bug that can corrupt data on traditional RAID systems.




\end{itemize}
\section{Theory: Ceph — Storage That Scales Across Many Machines}


ZFS is excellent for a single server’s storage. Ceph is for when you need storage that spans multiple physical machines. Ceph creates a single virtual storage pool from the disks of many servers. Data is automatically distributed and replicated across those disks.


Ceph’s key component: the CRUSH algorithm (Controlled Replication Under Scalable Hashing) determines where each piece of data is stored without any centralized lookup table. Every Ceph client can calculate the location of any data independently, enabling massive scaling without bottlenecks.

\section{Application: Setting Up ZFS on Proxmox}

\subsection{Create a ZFS pool in Proxmox}


\begin{alltt}

\# Check available disks:
lsblk

\# Create a mirrored ZFS pool (RAID-1 equivalent — requires 2 disks):
\# The pool will survive the failure of either disk.
zpool create tank mirror /dev/sdb /dev/sdc

\# Or a RAID-Z1 pool (RAID-5 equivalent — requires 3+ disks, can lose 1):
zpool create tank raidz /dev/sdb /dev/sdc /dev/sdd

\# Check pool status:
zpool status

\# Create a dataset for VM storage:
zfs create tank/vms
zfs set compression=on tank/vms    \# Enable transparent compression
zfs set atime=off tank/vms         \# Disable access time updates (performance)

\# Create a dataset for backups:
zfs create tank/backups
zfs set compression=on tank/backups

\# Take a snapshot (instant, no downtime):
zfs snapshot tank/vms@2024-01-15-14h30

\# List snapshots:
zfs list -t snapshot

\# Rollback to a snapshot (if something went wrong):
zfs rollback tank/vms@2024-01-15-14h30

\# Add ZFS pool to Proxmox:
\# In Proxmox web UI: Datacenter → Storage → Add → ZFS
\# Select your pool (tank) and name it (e.g. "local-zfs")

\end{alltt}

\section{Application: The 3-2-1 Backup System}

\subsection{Automated backup script using ZFS send\Slash{}receive}


\begin{alltt}

\#!/bin/bash
\# /opt/scripts/backup.sh
\# Sends ZFS snapshots to a remote backup location

DATASET="tank/vms"
REMOTE\_HOST="backup.yourdomain"        \# Remote server over WireGuard VPN
REMOTE\_USER="backup"
REMOTE\_DATASET="backup-pool/vms"
SNAPSHOT\_NAME="auto-\$(date +\%Y\%m\%d-\%H\%M)"

\# Create a new snapshot:
zfs snapshot "\$\{DATASET\}@\$\{SNAPSHOT\_NAME\}"

\# Get the most recent snapshot that was sent to the remote:
LAST\_REMOTE=\$(ssh "\$\{REMOTE\_USER\}@\$\{REMOTE\_HOST\}" \textbackslash{}
  "zfs list -t snapshot -H -o name \$\{REMOTE\_DATASET\} \textbar{} tail -1")

if [ -z "\$LAST\_REMOTE" ]; then
  \# First backup — send full snapshot:
  zfs send "\$\{DATASET\}@\$\{SNAPSHOT\_NAME\}" \textbar{} \textbackslash{}
    ssh "\$\{REMOTE\_USER\}@\$\{REMOTE\_HOST\}" \textbackslash{}
    "zfs receive \$\{REMOTE\_DATASET\}"
else
  \# Incremental backup — only send what changed:
  LAST\_LOCAL=\$(echo "\$LAST\_REMOTE" \textbar{} sed "s\textbar{}\$\{REMOTE\_DATASET\}\textbar{}\$\{DATASET\}\textbar{}")
  zfs send -i "\$\{LAST\_LOCAL\}" "\$\{DATASET\}@\$\{SNAPSHOT\_NAME\}" \textbar{} \textbackslash{}
    ssh "\$\{REMOTE\_USER\}@\$\{REMOTE\_HOST\}" \textbackslash{}
    "zfs receive \$\{REMOTE\_DATASET\}"
fi

\# Delete snapshots older than 30 days locally:
zfs list -t snapshot -H -o name "\$\{DATASET\}" \textbar{} \textbackslash{}
  head -n -30 \textbar{} xargs -I\{\} zfs destroy \{\}

echo "Backup completed: \$\{SNAPSHOT\_NAME\}"

\# Install as a daily cron job:
\# echo "0 3 * * * root /opt/scripts/backup.sh >> /var/log/backup.log 2>\&1" \textbackslash{}
\#   >> /etc/crontab

\end{alltt}

\chapter{Chapter 21: Databases — PostgreSQL and Redis}

\section{Theory: Why Your Applications Need Databases}


Every stateful service you run needs a place to persistently store data. Matrix stores messages and room state. XMPP stores roster lists and message history. Monitoring systems store metric time series. Databases provide:


\begin{itemize}
\item\relax 
\textbf{Persistence:} Data survives crashes and restarts



\item\relax 
\textbf{ACID properties:} Atomicity, Consistency, Isolation, Durability — guarantees that operations complete correctly or not at all



\item\relax 
\textbf{Querying:} Retrieve exactly the data you need efficiently



\item\relax 
\textbf{Replication:} Copy data to standby servers for high availability




\end{itemize}
\section{Theory: PostgreSQL — The Production-Grade Database}


PostgreSQL is a full-featured relational database. It is what Matrix Synapse uses as its backend (in production — the default SQLite is only for testing). PostgreSQL supports:


\begin{itemize}
\item\relax 
Streaming replication to standby servers (hot standby)



\item\relax 
Logical replication for selective data replication



\item\relax 
Row-level security (further limit what queries can access)



\item\relax 
Automatic failover with Patroni




\end{itemize}
\section{Theory: Redis — Fast In-Memory Storage}


Redis stores data in memory (RAM) rather than on disk, making it extremely fast. It is used as a cache (storing frequently-accessed data), a message queue (tasks waiting to be processed), and a session store (user login sessions). Matrix Synapse uses Redis for worker coordination.

\section{Application: PostgreSQL High Availability with Patroni}

\subsection{Setting up PostgreSQL with automatic failover}


\begin{alltt}

\# Install PostgreSQL on all nodes:
apt install postgresql-16 -y

\# Install Patroni (manages automatic failover):
apt install patroni -y

\# /etc/patroni/config.yml (example for 3-node cluster):
scope: postgres-ha-cluster
name: node1  \# Change to node2, node3 on other nodes

restapi:
  listen: 0.0.0.0:8008
  connect\_address: 10.2.0.1:8008  \# This node's IP

etcd:
  hosts:
    - 10.2.0.1:2379  \# etcd provides distributed state for Patroni
    - 10.2.0.2:2379
    - 10.2.0.3:2379

bootstrap:
  dcs:
    ttl: 30
    loop\_wait: 10
    retry\_timeout: 10
    maximum\_lag\_on\_failover: 1048576  \# 1MB — max allowed replication lag
  initdb:
    - encoding: UTF8
    - data-checksums           \# Enable data checksums

postgresql:
  listen: 0.0.0.0:5432
  connect\_address: 10.2.0.1:5432
  data\_dir: /var/lib/postgresql/16/main
  pgpass: /tmp/pgpass0
  authentication:
    replication:
      username: replicator
      password: STRONGPASSWORD
    superuser:
      username: postgres
      password: STRONGPASSWORD

\# Start Patroni:
systemctl enable --now patroni

\# Check cluster status:
patronictl -c /etc/patroni/config.yml list
\# Shows which node is primary, which are replicas, and replication lag

\end{alltt}

\chapter{Chapter 22: Containers — Docker, Podman, and LXC}

\section{Theory: Containers Are Not Virtual Machines}


Containers share the host OS kernel but isolate the process using Linux namespaces and cgroups (see Chapter 3). This makes them much lighter than VMs but with slightly weaker isolation. For most internal services (Matrix, IPFS, monitoring), containers are the right choice. For internet-facing services or untrusted code, use full VMs.


\textbf{Docker vs. Podman:} Docker requires a background daemon running as root — a security concern. Podman is rootless by design (containers run as a normal user, not root). For security-sensitive infrastructure, prefer Podman. For ease of use and Docker Compose compatibility, Docker is still widely used.

\section{Application: Running Matrix in Docker}

\subsection{Docker Compose file for Matrix + PostgreSQL}


\begin{alltt}

\# /opt/matrix/docker-compose.yml
version: '3.8'

services:
  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES\_USER: synapse
      POSTGRES\_PASSWORD: STRONGPASSWORD    \# Change this!
      POSTGRES\_DB: synapse
      POSTGRES\_INITDB\_ARGS: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C"
    volumes:
      - ./postgres-data:/var/lib/postgresql/data
    networks:
      - matrix-internal

  synapse:
    image: matrixdotorg/synapse:latest
    restart: unless-stopped
    depends\_on:
      - postgres
    volumes:
      - ./synapse-data:/data
    ports:
      - "8448:8448"    \# Federation port
      - "8008:8008"    \# Client API port
    networks:
      - matrix-internal
    environment:
      SYNAPSE\_SERVER\_NAME: "matrix.yourdomain.onion"
      SYNAPSE\_REPORT\_STATS: "no"

networks:
  matrix-internal:
    driver: bridge
    internal: true   \# No external internet access for this network

\# Start:
docker compose up -d

\# Check logs:
docker compose logs -f synapse

\end{alltt}


\noindent \textbf{LXC Containers in Proxmox}


Proxmox includes excellent support for LXC (Linux Containers) through its web interface. LXC containers in Proxmox are easier to manage than Docker for full services, support snapshots, and can be cloned and migrated like VMs. For each major service (Matrix, IPFS, XMPP, monitoring), consider creating a separate LXC container in Proxmox — it gives you clean isolation and easy management from the Proxmox web UI.

\part{Part VII — Automation \& Observability}


Making your infrastructure self-managing and self-reporting

\chapter{Chapter 23: Infrastructure as Code — Ansible and OpenTofu}

\subsection{Learning Objectives}


\begin{itemize}
\item\relax 
Understand the principle of Infrastructure as Code (IaC)



\item\relax 
Write basic Ansible playbooks to configure servers automatically



\item\relax 
Know when to use Ansible (configuration) vs. OpenTofu (provisioning)




\end{itemize}
\section{Theory: Why Infrastructure as Code Matters for Resistance}


Consider what happens when a key member of your infrastructure team is suddenly unavailable (arrested, forced to flee, ill). If configuration knowledge exists only in their head, your infrastructure cannot be maintained or rebuilt. Infrastructure as Code solves this: all configuration is in text files in a Git repository. Anyone with access to the repository and the encryption keys can reproduce the entire infrastructure.


\textbf{Ansible:} Agentless configuration management. You run it from your laptop; it SSHs into remote servers and configures them. You write “playbooks” — YAML files describing the desired state of a server.


\textbf{OpenTofu:} Infrastructure provisioning. It creates the servers, networks, and storage from text descriptions. Works with cloud providers (Hetzner, DigitalOcean, Linode) and local hypervisors (Proxmox).


OpenTofu builds the house (creates the VM, allocates the IP address, attaches the storage). Ansible furnishes and decorates the house (installs the software, writes the configuration files, starts the services). You need both for a complete infrastructure.

\section{Application: Writing an Ansible Playbook for WireGuard}

\subsection{Ansible playbook: configure WireGuard on all nodes}


\begin{alltt}

\# inventory.yml — list of servers to manage:
all:
  hosts:
    node-a:
      ansible\_host: 10.0.0.1    \# Management IP of each node
      wireguard\_ip: 10.2.0.1    \# WireGuard IP for this node
    node-b:
      ansible\_host: 10.0.0.2
      wireguard\_ip: 10.2.0.2
    node-c:
      ansible\_host: 10.0.0.3
      wireguard\_ip: 10.2.0.3

---
\# playbooks/wireguard.yml — the playbook:
- name: Configure WireGuard mesh VPN
  hosts: all
  become: true    \# Run as root

  tasks:
    - name: Install WireGuard
      apt:
        name: wireguard
        state: present
        update\_cache: yes

    - name: Generate private key if not present
      shell: \textbar{}
        wg genkey \textbar{} tee /etc/wireguard/private.key \textbar{} \textbackslash{}
        wg pubkey > /etc/wireguard/public.key
        chmod 600 /etc/wireguard/private.key
      args:
        creates: /etc/wireguard/private.key  \# Only run if file doesn't exist

    - name: Read private key
      slurp:
        src: /etc/wireguard/private.key
      register: private\_key

    - name: Write WireGuard interface config
      template:
        src: templates/wg0.conf.j2    \# Jinja2 template
        dest: /etc/wireguard/wg0.conf
        mode: '0600'

    - name: Enable and start WireGuard
      systemd:
        name: wg-quick@wg0
        enabled: yes
        state: started

\# Run the playbook:
\# ansible-playbook -i inventory.yml playbooks/wireguard.yml

\# Run only for one host:
\# ansible-playbook -i inventory.yml --limit node-a playbooks/wireguard.yml

\# Check what would change without making changes (dry run):
\# ansible-playbook -i inventory.yml playbooks/wireguard.yml --check

\end{alltt}

\section{Application: OpenTofu to Provision VMs on Proxmox}

\subsection{OpenTofu configuration for a Proxmox VM}


\begin{alltt}

\# main.tf
terraform \{
  required\_providers \{
    proxmox = \{
      source  = "bpg/proxmox"
      version = "\textasciitilde{}> 0.50"
    \}
  \}
\}

provider "proxmox" \{
  endpoint  = "https://192.168.1.10:8006"
  api\_token = "root@pam!terraform=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  insecure  = true    \# For self-signed cert (replace with real cert)
\}

\# Create a VM from a cloud-init template:
resource "proxmox\_virtual\_environment\_vm" "matrix\_server" \{
  name      = "matrix-server"
  node\_name = "proxmox-node1"
  vm\_id     = 101

  cpu \{
    cores = 4
    type  = "x86-64-v2-AES"
  \}

  memory \{
    dedicated = 8192    \# 8 GB RAM
  \}

  disk \{
    datastore\_id = "local-zfs"
    file\_id      = "local:iso/ubuntu-24.04-server.img"
    size         = 50   \# 50 GB
  \}

  network\_device \{
    bridge = "vmbr0"
  \}

  \# Cloud-init configuration:
  initialization \{
    ip\_config \{
      ipv4 \{
        address = "10.1.0.10/24"
        gateway = "10.1.0.1"
      \}
    \}
    user\_account \{
      username = "ansible"
      keys     = [file("\textasciitilde{}/.ssh/id\_ed25519.pub")]  \# Your SSH public key
    \}
  \}
\}

\# Deploy:
\# tofu init
\# tofu plan    \# Preview what will be created
\# tofu apply   \# Create the VM

\end{alltt}

\chapter{Chapter 24: Monitoring — Seeing What Is Happening}

\section{Theory: The Observability Stack}


Observability is the ability to understand the internal state of a system from its external outputs. It has three pillars:


\begin{itemize}
\item\relax 
\textbf{Metrics:} Numerical measurements over time (CPU \%, requests\Slash{}second, queue depth)



\item\relax 
\textbf{Logs:} Timestamped records of events (“user logged in”, “error: database connection failed”)



\item\relax 
\textbf{Traces:} Records of how a single request flows through multiple services




\end{itemize}

For a resistance network, you primarily need metrics and logs. The monitoring stack:

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|}
\hline
\relax  Tool  &  Pillar  &  Job   \\
\hline
\relax  \textbf{Node Exporter}  &  Metrics  &  Exports Linux system metrics (CPU, RAM, disk, network) for Prometheus to collect   \\
\relax  \textbf{cAdvisor}  &  Metrics  &  Exports container metrics (Docker\Slash{}Podman container resource usage)   \\
\relax  \textbf{Prometheus}  &  Metrics  &  Scrapes (collects) metrics from all exporters every 15 seconds; stores them in a time-series database   \\
\relax  \textbf{Alertmanager}  &  Metrics  &  Receives alert rules from Prometheus; routes and deduplicates alerts; sends to Matrix\Slash{}email   \\
\relax  \textbf{Loki}  &  Logs  &  Collects and indexes logs from all services; searchable like Prometheus metrics   \\
\relax  \textbf{Grafana}  &  Both  &  Visualization: dashboards for metrics (from Prometheus) and logs (from Loki)   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip

\section{Application: Deploying the Monitoring Stack}

\subsection{Deploy Prometheus + Grafana + Loki with Docker Compose}


\begin{alltt}

\# /opt/monitoring/docker-compose.yml
version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    restart: unless-stopped
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    ports:
      - "127.0.0.1:9090:9090"   \# Only accessible from localhost
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.retention.time=90d'  \# Keep 90 days of data

  grafana:
    image: grafana/grafana:latest
    restart: unless-stopped
    volumes:
      - grafana-data:/var/lib/grafana
    ports:
      - "127.0.0.1:3000:3000"   \# Access via SSH tunnel or VPN only
    environment:
      GF\_AUTH\_ANONYMOUS\_ENABLED: "false"
      GF\_SECURITY\_ADMIN\_PASSWORD: "STRONGPASSWORD"

  loki:
    image: grafana/loki:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:3100:3100"
    command: -config.file=/etc/loki/local-config.yaml

  alertmanager:
    image: prom/alertmanager:latest
    restart: unless-stopped
    volumes:
      - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
    ports:
      - "127.0.0.1:9093:9093"

volumes:
  prometheus-data:
  grafana-data:

\end{alltt}

\subsection{Prometheus configuration: scrape targets}


\begin{alltt}

\# /opt/monitoring/prometheus.yml
global:
  scrape\_interval: 15s

scrape\_configs:
  - job\_name: 'node-exporters'
    static\_configs:
      - targets:
        - '10.2.0.1:9100'   \# Node A — Node Exporter
        - '10.2.0.2:9100'   \# Node B — Node Exporter
        - '10.2.0.3:9100'   \# Node C — Node Exporter

  - job\_name: 'cadvisor'
    static\_configs:
      - targets:
        - '10.2.0.1:8080'   \# Container metrics from Node A

  - job\_name: 'matrix-synapse'
    metrics\_path: '/\_synapse/metrics'
    static\_configs:
      - targets:
        - '10.2.0.2:8008'

rule\_files:
  - 'alerts.yml'

alerting:
  alertmanagers:
    - static\_configs:
      - targets: ['alertmanager:9093']

\end{alltt}

\subsection{Alerting rules: critical alerts for resistance infrastructure}


\begin{alltt}

\# /opt/monitoring/alerts.yml
groups:
  - name: critical
    rules:
      - alert: ServiceDown
        expr: up == 0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Service \{\{ \$labels.job \}\} on \{\{ \$labels.instance \}\} is down"

      - alert: DiskSpaceLow
        expr: (node\_filesystem\_avail\_bytes / node\_filesystem\_size\_bytes) < 0.15
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Disk space below 15\% on \{\{ \$labels.instance \}\}"

      - alert: HighMemoryUsage
        expr: (1 - (node\_memory\_MemAvailable\_bytes / node\_memory\_MemTotal\_bytes)) > 0.90
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Memory usage above 90\% on \{\{ \$labels.instance \}\}"

      - alert: WireGuardPeerDown
        expr: wireguard\_peer\_last\_handshake\_seconds > 180
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "WireGuard peer has not handshaked in 3 minutes"

\end{alltt}

\part{Part VIII — Security}


Protecting infrastructure, data, and people

\chapter{Chapter 25: Threat Modeling — Know Your Adversary}

\section{Theory: The STRIDE Framework}


Threat modeling is the practice of systematically identifying what can go wrong before it does. The STRIDE framework is a structured way to think through threats:

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|}
\hline
\relax  Letter  &  Threat  &  Example in our context   \\
\hline
\relax  S  &  Spoofing (pretending to be someone else)  &  Adversary impersonates a trusted peer’s WireGuard identity   \\
\relax  T  &  Tampering (modifying data)  &  Adversary alters a published document in transit   \\
\relax  R  &  Repudiation (denying you did something)  &  Member denies sending a message — or falsely accused   \\
\relax  I  &  Information Disclosure (data leaks)  &  Unencrypted logs containing IP addresses or usernames   \\
\relax  D  &  Denial of Service (making service unavailable)  &  DDoS attack against your Matrix server   \\
\relax  E  &  Elevation of Privilege (gaining unauthorized access)  &  Attacker exploits a Synapse bug to gain root access   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip

\section{Application: Building Your Threat Model}

\subsection{Four questions to answer before building anything}


\begin{enumerate}[1.]
\item\relax 
\textbf{What assets am I protecting?} List: message content, member identities, server locations, operational plans, document cache.



\item\relax 
\textbf{Who are my adversaries?} Are they a local police department? A national intelligence agency? A criminal group? Each has different capabilities.



\item\relax 
\textbf{What are my adversary’s capabilities?} Can they do passive monitoring only? Can they conduct raids? Can they compromise global internet infrastructure?



\item\relax 
\textbf{What is my acceptable risk?} What threats am I willing to accept vs. what must I defend against at all costs?




\end{enumerate}
\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|}
\hline
\relax  Adversary  &  Capabilities  &  Primary defenses   \\
\hline
\relax  Local law enforcement  &  Seize devices; access ISP records; limited technical capability  &  Full disk encryption; traffic encryption; no logs   \\
\relax  National intelligence  &  Mass surveillance; legal demands to providers; limited hacking  &  Tor; self-hosted infrastructure; no third-party providers   \\
\relax  Nation-state intelligence  &  Zero-day exploits; compromising update infrastructure; human infiltration  &  Air-gapped systems; open hardware; need-to-know principle; physical security   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip

\chapter{Chapter 26: Cryptography From First Principles}

\section{Theory: Symmetric Encryption}


Symmetric encryption uses the same key to encrypt and decrypt. It is fast — modern CPUs can encrypt gigabytes per second using hardware instructions. The challenge: how do you securely share the key with the other party in the first place?


Used for: encrypting data at rest (disk encryption with LUKS), bulk data transfer inside an established VPN tunnel.


\textbf{AES-256-GCM} is the modern standard. The “256” means a 256-bit key — there are 2²⁵⁶ possible keys, a number larger than the number of atoms in the observable universe. Brute-forcing it is computationally impossible.

\section{Theory: Asymmetric (Public-Key) Encryption}


Asymmetric encryption uses a \emph{pair} of mathematically related keys. What one key encrypts, only the other can decrypt. It solves the key exchange problem: you can publish your public key openly; anyone can encrypt a message with it that only your private key can decrypt.


\textbf{Key pair uses:}


\begin{itemize}
\item\relax 
\textbf{Encryption:} Encrypt with recipient’s public key → only recipient’s private key can decrypt



\item\relax 
\textbf{Signing:} Sign with your own private key → anyone with your public key can verify the signature is genuine




\end{itemize}

\textbf{Diffie-Hellman Key Exchange:} How two parties agree on a shared secret key over an insecure channel — without ever sending the key itself. This is what enables the initial handshake in WireGuard, TLS, and Signal’s Double Ratchet protocol.

\section{Theory: The Double Ratchet Algorithm (Signal, Matrix OMEMO)}


The Double Ratchet is what makes Signal, Matrix (E2EE rooms), and XMPP (OMEMO) resistant even to key compromise. It has two ratchets:


\begin{itemize}
\item\relax 
\textbf{Diffie-Hellman ratchet:} New Diffie-Hellman keys are exchanged with every message, ensuring that even if a key is compromised, only recent messages are at risk (perfect forward secrecy)



\item\relax 
\textbf{Symmetric ratchet:} Each message derives a new key from the previous one, so past and future messages remain secure even if one message key is compromised




\end{itemize}

Each message uses a different key. Keys are derived sequentially from a master key, like pages torn from a pad — once used and destroyed, they are gone. Capturing message 15’s key tells you nothing about messages 1–14 (past) or 16+ (future). This property is called “forward secrecy” and “break-in recovery.”

\section{Application: Practical Cryptography Tools}

\subsection{GPG: encrypting files and email}


\begin{alltt}

\# Generate a GPG key pair:
gpg --full-gen-key
\# Choose: RSA and RSA, key size 4096, no expiry (or set an expiry for security)
\# Provide: your pseudonym (NOT your real name), a pseudonymous email

\# Export your public key (share this with people who want to send you encrypted files):
gpg --armor --export yourpseudo@example.com > yourpseudo-public.asc

\# Import someone else's public key:
gpg --import theirpseudo-public.asc

\# Encrypt a file for a recipient (they use their private key to decrypt):
gpg --encrypt --armor --recipient theirpseudo@example.com secret-document.pdf

\# Decrypt a file encrypted for you:
gpg --decrypt secret-document.pdf.asc

\# Sign a file (proves it came from you, without encrypting it):
gpg --detach-sign --armor document.pdf
\# Creates document.pdf.asc (the signature file)

\# Verify a signature:
gpg --verify document.pdf.asc document.pdf

\end{alltt}

\subsection{LUKS: full disk encryption}


\begin{alltt}

\# Encrypt a new disk/partition with LUKS:
\# WARNING: This destroys all data on the disk. Back up first!
cryptsetup luksFormat /dev/sdb

\# Open (unlock) an encrypted disk:
cryptsetup open /dev/sdb encrypted-disk

\# Now format and use it:
mkfs.ext4 /dev/mapper/encrypted-disk
mount /dev/mapper/encrypted-disk /mnt/secure

\# Close (lock) when done:
umount /mnt/secure
cryptsetup close encrypted-disk

\# For automatic unlock at boot (e.g., using a key file stored on a trusted USB):
\# /etc/crypttab:
\# encrypted-disk UUID=xxxx /path/to/keyfile luks

\end{alltt}

\chapter{Chapter 27: Operational Security — The Human Layer}

\section{Theory: Why Technology Alone Is Not Enough}


The most common cause of compromise in real-world resistance operations is not technical — it is human. Someone tells the wrong person. Someone logs in from home when they should use Tor. Someone uses the same username on two different platforms. Someone loses a device with unencrypted data.


OpSec (Operational Security) is the discipline of minimizing information leakage through human behavior. It originated in military intelligence and has been adapted by journalists, activists, and security researchers.

\section{Theory: The Five-Step OpSec Process}


\begin{enumerate}[1.]
\item\relax 
\textbf{Identify critical information:} What do you need to protect? Member identities, server locations, operational plans, communications content, financial resources.



\item\relax 
\textbf{Analyze threats:} Who wants this information? What are they willing and able to do to get it?



\item\relax 
\textbf{Analyze vulnerabilities:} Where are the gaps between what you need to protect and how well you are protecting it?



\item\relax 
\textbf{Assess risk:} For each vulnerability, how likely is exploitation and how damaging would it be?



\item\relax 
\textbf{Apply counter-measures:} Implement the measures that address the highest-risk vulnerabilities.




\end{enumerate}
\section{Application: OpSec Checklist}

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|}
\hline
\relax  Practice  &  Why  &  How   \\
\hline
\relax  Compartmentalize  &  Limit damage from any single person being compromised  &  Divide operations into cells; no member knows members of other cells; need-to-know only   \\
\relax  Separate identities  &  Linking a pseudonym to a real identity compromises both  &  Different devices, different usernames, different email addresses for different roles   \\
\relax  Use Tor for sensitive browsing  &  Your ISP can see what IP addresses you connect to even if traffic is encrypted  &  Always use Tor Browser for anything related to your work   \\
\relax  No phone in secure locations  &  Phones track location via cell towers even without GPS; microphones can be exploited  &  Leave phones at home or in a Faraday bag during sensitive meetings   \\
\relax  Verify before trusting  &  Infiltrators are a real threat; anyone can claim to be trustworthy  &  Cryptographic key verification; vouching chains; in-person introduction   \\
\relax  Minimize data retention  &  Data that does not exist cannot be seized or leaked  &  Delete messages after reading; use self-destructing message settings; minimal logging   \\
\relax  Encrypt everything at rest  &  Seized hardware reveals nothing if encrypted  &  LUKS on all drives; VeraCrypt for portable encrypted volumes   \\
\relax  Strong unique passwords  &  Reused passwords compromise multiple accounts when one is breached  &  Use Bitwarden (self-hosted) or KeePassXC (local); generate 20+ character random passwords   \\
\relax  Hardware MFA  &  Software TOTP codes can be phished; hardware keys cannot  &  YubiKey or SoloKey for all critical accounts   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip


\noindent \textbf{Metadata: The Information You Forget to Hide}


Even with perfect message encryption, metadata reveals a great deal: who communicated with whom, when, how often, and for how long. An intelligence agency does not need to read your messages if they can infer from metadata that you called the journalist in the hour before the article was published. Counter-measure: Tor hides destination metadata from your ISP. Matrix over a private server reduces the metadata exposed to third parties. But only reducing contact frequency and using dead-drops truly minimizes metadata.

\part{Part IX — Radio}


Communicating when the internet is completely gone

\chapter{Chapter 28: Radio Fundamentals and the Spectrum}

\subsection{Learning Objectives}


\begin{itemize}
\item\relax 
Understand what radio waves are and how they travel



\item\relax 
Know which frequency bands are useful for different scenarios



\item\relax 
Understand modulation — how information is encoded onto radio waves




\end{itemize}
\section{Theory: What Radio Waves Are}


Radio waves are electromagnetic radiation — the same physical phenomenon as visible light, X-rays, and microwaves, just at different frequencies. They propagate (travel) at the speed of light and can travel through air, vacuum, and some materials without any infrastructure.


Key properties:


\begin{itemize}
\item\relax 
\textbf{Frequency:} How many times per second the wave oscillates. Measured in Hertz (Hz). Higher frequency = more oscillations per second.



\item\relax 
\textbf{Wavelength:} The physical distance between two wave peaks. Wavelength = speed of light \Slash{} frequency. Higher frequency = shorter wavelength.



\item\relax 
\textbf{Power:} How strong the signal is. Measured in Watts. More power = farther range (but also more detectability).




\end{itemize}
\section{Theory: How Different Frequencies Travel}

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|X|X|}
\hline
\relax  Frequency  &  Name  &  How It Travels  &  Range  &  Use   \\
\hline
\relax  3–30 MHz  &  HF (High Frequency) \Slash{} Shortwave  &  Bounces off the ionosphere (sky wave) — can travel around the world  &  Global  &  International shortwave radio; best for long-range resistance comms   \\
\relax  30–300 MHz  &  VHF (Very High Frequency)  &  Line-of-sight; some ducting (atmospheric bounce)  &  City\Slash{}regional (30–300 km with good antennas)  &  FM radio; aviation comms; emergency services   \\
\relax  300 MHz–3 GHz  &  UHF (Ultra High Frequency)  &  Line-of-sight; penetrates walls  &  Local (1–50 km)  &  Wi-Fi; mobile phones; walkie-talkies   \\
\relax  865–928 MHz  &  LoRa ISM band  &  Line-of-sight with penetration  &  2–15 km urban; up to 40 km rural  &  Low-power digital messages without internet   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip

\section{Theory: Modulation — Encoding Information onto Radio}


A radio wave by itself (a “carrier wave”) carries no information. Modulation changes some property of the carrier wave to encode information:

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|X|}
\hline
\relax  Modulation  &  What Changes  &  Characteristics  &  Use   \\
\hline
\relax  \textbf{AM (Amplitude Modulation)}  &  The strength (amplitude) of the wave  &  Simple; susceptible to interference; travels far on HF  &  Standard AM radio broadcasting   \\
\relax  \textbf{FM (Frequency Modulation)}  &  The frequency of the wave  &  Better audio quality; more resistant to static  &  FM radio broadcasting; walkie-talkies   \\
\relax  \textbf{SSB (Single Sideband)}  &  A single sideband of an AM signal  &  Very efficient — 3x the range of AM for the same power; standard for HF voice  &  Amateur radio HF voice; maritime radio   \\
\relax  \textbf{CW (Morse Code)}  &  Turning the carrier on and off  &  Extremely narrow bandwidth; cuts through interference; works when voice cannot  &  Emergency communications; long-distance HF   \\
\relax  \textbf{FSK (Frequency Shift Keying)}  &  Alternates between two frequencies to represent 0 and 1  &  Robust digital mode  &  APRS; packet radio; low-rate data   \\
\relax  \textbf{LoRa (Long Range)}  &  Chirp spread spectrum (frequency sweeps)  &  Extremely long range at very low power; digital  &  IoT sensors; message networks without internet   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip


\noindent \textbf{The Most Important Radio Skill: Listening}


Before you transmit anything, spend time listening. An RTL-SDR receiver costs \$25 and lets you listen to virtually everything across a huge frequency range. Listen to emergency services, aviation communications, weather satellites, and shortwave broadcasts in your area. Understanding what frequencies are used for what, and where transmissions originate, is invaluable intelligence for any operation — and requires no license to do.

\chapter{Chapter 29: Software Defined Radio — Hardware and Software}

\section{Theory: What “Software Defined” Means}


A traditional radio is hardware-defined: its circuitry determines what it can receive and transmit, at what frequencies, and using what modulation. To change what it does, you need different hardware.


A Software Defined Radio (SDR) replaces most of that hardware with a general-purpose analog-to-digital converter (ADC) and a computer. The ADC samples raw radio signals at very high speed. The computer then performs all the signal processing in software — filtering, demodulation, decoding. To receive a different mode, you load different software — or write your own.

\section{Theory: IQ Sampling in Plain Language}


To fully capture a radio signal, you need to know two things at each moment: its amplitude (strength) and its phase (where it is in its cycle). A single measurement at one point in time tells you only amplitude. IQ sampling captures both by measuring the signal twice simultaneously, 90 degrees apart in phase.


These two measurements are called the “I” (In-phase) component and the “Q” (Quadrature — 90 degrees offset) component. Together, they fully describe the signal, enabling any type of demodulation in software.

\section{Application: SDR Hardware Comparison}

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|X|X|}
\hline
\relax  Device  &  Frequency Range  &  TX\Slash{}RX  &  Cost  &  Best For   \\
\hline
\relax  \textbf{RTL-SDR Blog V4}  &  500 kHz – 1.7 GHz  &  RX only  &  \$35  &  First device; listening, monitoring, ADS-B, weather sats   \\
\relax  \textbf{HackRF One}  &  1 MHz – 6 GHz  &  TX+RX (half-duplex)  &  \$300  &  Versatile experimentation; transmitting; signal analysis   \\
\relax  \textbf{LimeSDR Mini 2}  &  10 MHz – 3.5 GHz  &  TX+RX (full-duplex)  &  \$250  &  Two-way communications; higher performance than HackRF   \\
\relax  \textbf{PlutoSDR (ADALM-PLUTO)}  &  325 MHz – 3.8 GHz  &  TX+RX  &  \$150  &  Learning; good documentation; medium performance   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip

\section{Application: Setting Up SDR++ for Monitoring}

\subsection{Install and use SDR++ (Linux)}


\begin{alltt}

\# Download SDR++ AppImage from sdrpp.org/downloads:
wget https://github.com/AlexandreRouma/SDRPlusPlus/releases/download/nightly/sdrpp\_linux\_amd64.AppImage
chmod +x sdrpp\_linux\_amd64.AppImage

\# Plug in your RTL-SDR, run SDR++:
./sdrpp\_linux\_amd64.AppImage

\# In SDR++:
\# 1. Source → Select "RTL-SDR"
\# 2. Click "Play" button to start receiving
\# 3. Click on the frequency display and type a frequency
\# 4. Select demodulation mode (AM/FM/SSB/CW) from the dropdown
\# 5. Adjust the waterfall contrast to see signals clearly

\# Useful frequencies to monitor (vary by country):
\# - 121.5 MHz: International aviation emergency frequency
\# - 156.8 MHz: Marine Channel 16 (international distress)
\# - 162.4-162.55 MHz: NOAA Weather Radio (US)
\# - 406-406.1 MHz: Emergency Position Indicating Radio Beacons (EPIRBs)
\# - 1090 MHz: ADS-B aircraft transponders (decode with dump1090)

\end{alltt}

\subsection{Decode ADS-B aircraft positions in real time}


\begin{alltt}

\# Install dump1090 (ADS-B decoder):
apt install dump1090-fa -y

\# Run with your RTL-SDR connected:
dump1090 --net --interactive

\# View aircraft positions at:
\# http://localhost:8080

\# This shows every aircraft within range broadcasting its
\# position, altitude, speed, and flight number — no internet needed.
\# Useful for tracking movements in your area.

\end{alltt}

\chapter{Chapter 30: Building a Radio Communication Node}

\section{The Complete Radio Stack for a Resistance Node}


A fully equipped radio node provides communication capability at every scale — from local (mesh\Slash{}Wi-Fi) to continental (HF shortwave) — without depending on any internet infrastructure.

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|X|}
\hline
\relax  Layer  &  Equipment  &  Range  &  Purpose   \\
\hline
\relax  Local  &  Wi-Fi router running BATMAN-adv, Raspberry Pi  &  100–500m  &  Local mesh when internet is down   \\
\relax  City  &  RTL-SDR or HackRF + directional antenna  &  5–30 km  &  Monitoring; APRS messaging   \\
\relax  Regional  &  LoRa gateway (e.g., RAK WisGate) or HF transceiver  &  40–200 km  &  Regional coordination without internet   \\
\relax  Continental  &  HF SSB transceiver (e.g., Icom IC-7300) + dipole antenna  &  World  &  Long-distance coordination; news reception from free broadcasters   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip

\section{Application: APRS — Radio Text Messaging Without Internet}

\subsection{Set up an APRS digipeater and message gateway}


\begin{alltt}

\# Install Dire Wolf (APRS software modem/digipeater):
apt install direwolf -y

\# /etc/direwolf.conf:
ADEVICE default             \# Use default sound card (or RTL-SDR via rtl\_fm)
CHANNEL 0
MYCALL CALLSIGN-9           \# Your APRS callsign (requires amateur radio license)
MODEM 1200                  \# 1200 baud AFSK (standard APRS)

\# Digipeater (repeat received packets to extend range):
DIGIPEAT 0 0 \^{}WIDE[3-7]-[3-7]\$ \^{}WIDE[12]-[12]\$

\# I-Gate (connect APRS to internet when available):
\# IGSERVER rotate.aprs2.net
\# IGLOGIN CALLSIGN-9 PASSCODE

\# Run Dire Wolf:
direwolf -c /etc/direwolf.conf

\# Send a message from another APRS device:
\# Use any APRS app (APRSDroid on Android) — your gateway
\# will receive and relay it.

\# Without a license (listen-only mode):
\# Remove MYCALL and DIGIPEAT lines; just monitor
rtl\_fm -f 144.39M -s 22050 \textbar{} direwolf -c /dev/stdin -r 22050 -n 1

\end{alltt}


\noindent \textbf{LoRa Mesh Networks: No License Required}


LoRa operates in license-free ISM (Industrial, Scientific, Medical) bands in most countries. The Meshtastic project (meshtastic.org) provides open-source firmware for LoRa devices that creates a text message mesh network. Each node repeats messages from others, extending range. A \$30 LoRa module running Meshtastic can send text messages to another node 10+ km away — completely without internet, cellular, or any infrastructure.

\part{Part X — Putting It All Together}


Reliability engineering, progressive lab design, and reference material

\chapter{Chapter 31: Reliability Engineering — When Things Break}

\section{Theory: Failure Modes and Their Probabilities}


In reliability engineering, we think in terms of failure modes — the specific ways a system can fail — and design against each one. For a resistance network, failure modes include:

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|X|}
\hline
\relax  Failure Mode  &  Probability  &  Impact  &  Counter-measure   \\
\hline
\relax  Hard drive failure  &  High (1–5\% per drive per year)  &  Data loss; service outage  &  ZFS mirror; regular backups   \\
\relax  Power outage  &  Medium (depends on location)  &  Service outage  &  UPS battery backup; generator   \\
\relax  ISP outage or throttling  &  High (in an authoritarian context)  &  Loss of internet connectivity  &  Second ISP; 4G backup; radio   \\
\relax  Physical raid\Slash{}seizure  &  Low-Medium  &  Total loss of one site  &  Geographic distribution; remote backups   \\
\relax  Software vulnerability exploit  &  Medium  &  Service compromise; data breach  &  Regular updates; minimal attack surface; network segmentation   \\
\relax  Operator error  &  High  &  Varies widely  &  Infrastructure as Code; dry-run testing; change management   \\
\relax  Member arrest\Slash{}departure  &  Medium  &  Loss of institutional knowledge  &  Documentation; multiple operators per system   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip

\section{Theory: RPO and RTO}


\textbf{Recovery Point Objective (RPO):} The maximum acceptable amount of data loss, measured in time. If you back up every 4 hours, your RPO is 4 hours — in the worst case, you could lose 4 hours of messages. For critical communications data, target RPO of 1 hour or less.


\textbf{Recovery Time Objective (RTO):} The maximum acceptable time for a service to be unavailable after a failure. For critical communications (Matrix, XMPP), target RTO of 30 minutes or less. For non-critical services (monitoring, file archival), RTO of several hours may be acceptable.

\section{Application: Chaos Engineering Exercises}

\subsection{Monthly resilience drills}


\begin{alltt}

\# Exercise 1: Node failure
\# Shut down Node A completely (without warning the team):
proxmox: Right-click VM → Stop

\# Observe:
\# - Does Matrix automatically fail over to Node B? (Yes if HA is configured)
\# - Do WireGuard peers reconnect automatically? (Yes — persistent keepalive)
\# - Do Prometheus alerts fire within 2 minutes? (Check Alertmanager)
\# - Can users still send messages? (Check on client apps)

\# Exercise 2: Disk failure simulation
\# On a running ZFS mirror, offline one disk:
zpool offline tank sdb

\# Observe:
\# - Does `zpool status` show the pool as DEGRADED? (It should)
\# - Do services continue running? (Yes — mirror still has one disk)
\# - Does Prometheus alert on the degraded pool? (Configure this alert)

\# Replace the "failed" disk and restore the mirror:
zpool online tank sdb   \# Re-online the test disk

\# Exercise 3: Backup restore drill
\# Take a real backup and restore it to a fresh VM:
\# 1. Create a new VM in Proxmox
\# 2. Restore your latest Matrix backup
\# 3. Start the service
\# 4. Verify messages are accessible
\# 5. Measure how long this took — target: under 30 minutes

\# Exercise 4: Internet cutoff
\# Unplug the WAN connection (or block it with nftables):
nft add rule inet filter output oif eth0 drop comment "Simulate WAN cutoff"

\# Observe:
\# - Does local mesh (BATMAN-adv) still work? (It should)
\# - Can users communicate via the local Matrix server? (If it is on the local mesh, yes)
\# - Do Tor onion services still work? (Yes — Tor is already on the mesh)

\# Restore:
nft delete rule inet filter output oif eth0 drop

\end{alltt}

\chapter{Chapter 32: Progressive Lab Design — Small to Regional}

\section{Scale 1: Individual or Pair — The “Go Bag” Lab}


A single machine that can be set up quickly at any location. Prioritizes portability and speed of deployment over redundancy.


\begin{alltt}

Hardware:
  - 1x refurbished laptop or mini PC
  - 1x 1 TB SSD (external, encrypted)
  - 1x RTL-SDR dongle + antenna
  - 1x 4G USB modem (backup internet)
  - 1x TP-Link TL-MR3020 (travel router for local network)

Software stack:
  - Proxmox VE on the laptop
  - WireGuard (connect to other trusted peers)
  - Matrix Synapse (personal homeserver)
  - Tor (for browsing and onion services)
  - IPFS (for document sharing)

Setup time: 2 hours (first time); 30 minutes with Ansible playbook
Cost: \$200-400 (depending on what you have)

\end{alltt}

\section{Scale 2: Small Group — The Community Hub}


\begin{alltt}

Hardware (per location — aim for 2 locations):
  - 3x mini PCs or refurbished desktops (e.g., Intel NUC, HP EliteDesk)
  - 16 GB RAM each, 500 GB SSD each
  - 1x 8-port managed switch (VLAN-capable)
  - 1x UPS battery backup
  - 1x RTL-SDR + outdoor antenna (on a tripod or window mount)
  - 1x 4G router for backup internet

Network diagram:
  Location A:                Location B:
  [Node A1]─[Node A2]       [Node B1]
      \textbar{}    ×    \textbar{}                \textbar{}
  [Switch A]               [Switch B]
      \textbar{}                        \textbar{}
  [Router A]               [Router B]
      \textbar{}                        \textbar{}
  [Internet A]            [Internet B]
      └──────────WireGuard VPN───────┘

Services:
  Matrix: Primary on A1, replica on A2, cold standby on B1
  PostgreSQL: 3-node cluster (A1 + A2 + B1) with Patroni
  IPFS: All 3 nodes pin critical content
  Monitoring: Prometheus on B1 (separate from what it monitors)

Monthly cost: \textasciitilde{}\$0 (hardware is one-time; electricity is low for mini PCs)

\end{alltt}

\section{Scale 3: Regional Network — The Distributed Collective}


\begin{alltt}

Multiple cities, each with 2-3 nodes:

City A ──── City B ──── City C
  │              │           │
  └──────────────┴───────────┘
        Yggdrasil + WireGuard mesh overlay

Within each city: BATMAN-adv Wi-Fi mesh for local comms without WAN
Between cities: WireGuard tunnels over whatever internet is available
Fallback: HF radio stations in each city for when all internet is cut

Services architecture:
  Each city: runs own Matrix homeserver (federated with other cities)
  Each city: runs own XMPP server (federated)
  Each city: runs own IPFS pinning cluster
  Each city: runs own Tor bridge relay
  One location: runs Asterisk for voice coordination
  All locations: contribute to Prometheus federation for global monitoring

Capacity planning per city (serves \textasciitilde{}50 active users):
  Storage: 2 TB (messages + files) → grows \textasciitilde{}100 GB/year at moderate usage
  RAM: 32 GB (Matrix + PostgreSQL + IPFS + monitoring)
  Bandwidth: 50 Mbps (adequate for 50 users)
  Backup: 6 TB offsite (3x 2 TB rotating)

\end{alltt}

\section{Network Topology Templates}


\textbf{IP addressing scheme (consistent across all scales):}

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|}
\hline
\relax  Subnet  &  Purpose  &  Notes   \\
\hline
\relax  10.0.0.0\Slash{}24  &  Management  &  Admin access, Proxmox UI, SSH — restrict to trusted admin IPs only   \\
\relax  10.1.0.0\Slash{}24  &  Services  &  Matrix, XMPP, IPFS, Asterisk containers   \\
\relax  10.2.0.0\Slash{}24  &  WireGuard VPN mesh  &  All nodes’ WireGuard tunnel addresses   \\
\relax  10.3.0.0\Slash{}24  &  Monitoring  &  Prometheus, Grafana, Loki   \\
\relax  192.168.100.0\Slash{}24  &  BATMAN-adv mesh  &  Local physical mesh addresses   \\
\relax  200::\Slash{}7  &  Yggdrasil  &  Auto-assigned from public key; globally unique within Yggdrasil   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip


\textbf{VLAN plan:}

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|X|}
\hline
\relax  VLAN ID  &  Name  &  Traffic  &  Access Policy   \\
\hline
\relax  10  &  Management  &  SSH, Proxmox UI, Ansible  &  Admin IPs only; no internet access   \\
\relax  20  &  Services  &  Matrix, XMPP, IPFS ports  &  VPN peers can reach; internet via Tor only   \\
\relax  30  &  Monitoring  &  Prometheus scrape, Grafana  &  Management VLAN only; no external access   \\
\relax  40  &  External  &  Public-facing (via Tor onion)  &  Strict egress; only Tor port 9050 outbound   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip

\chapter{Chapter 33: Quick Reference and Appendices}

\section{Priority Order: What to Build First}

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|X|}
\hline
\relax  Priority  &  What  &  Why  &  Effort   \\
\hline
\relax  1 — Critical  &  Full disk encryption on all machines  &  Seized hardware reveals nothing  &  1 hour   \\
\relax  2 — Critical  &  WireGuard mesh VPN between all nodes  &  Encrypted backbone for all services  &  2–4 hours   \\
\relax  3 — Critical  &  Matrix homeserver on Tor onion  &  Primary encrypted group communication  &  4–8 hours   \\
\relax  4 — High  &  Automated backups (ZFS + offsite)  &  Survive seizure of one location  &  2–4 hours   \\
\relax  5 — High  &  Tor Browser + Tor bridges configured  &  Anonymous access when Tor is blocked  &  30 minutes   \\
\relax  6 — High  &  IPFS node with critical documents pinned  &  Censorship-resistant publishing  &  2 hours   \\
\relax  7 — Medium  &  RTL-SDR + monitoring setup  &  Situational awareness; radio fallback  &  2 hours   \\
\relax  8 — Medium  &  Monitoring stack (Prometheus + Grafana)  &  Know when things fail  &  4–6 hours   \\
\relax  9 — Medium  &  BATMAN-adv local mesh  &  Communicate if internet is cut  &  4–8 hours   \\
\relax  10 — Medium  &  HF\Slash{}LoRa radio capability  &  Ultimate fallback  &  Variable (requires equipment)   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip

\section{Complete Software Toolkit}

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|X|}
\hline
\relax  Category  &  Tool  &  Purpose  &  Where to Get   \\
\hline
\relax  Hypervisor  &  Proxmox VE  &  Run VMs and containers  &  proxmox.com   \\
\relax  VPN  &  WireGuard  &  Encrypted mesh VPN  &  wireguard.com   \\
\relax  Mesh  &  BATMAN-adv  &  Local Wi-Fi mesh  &  open-mesh.org   \\
\relax  Overlay  &  Yggdrasil  &  Self-organizing encrypted network  &  yggdrasil-network.github.io   \\
\relax  Anonymity  &  Tor  &  Anonymous routing + onion services  &  torproject.org   \\
\relax  Anonymity  &  I2P  &  Hidden internal services  &  geti2p.net   \\
\relax  Messaging  &  Matrix (Synapse)  &  Federated encrypted group chat  &  matrix.org   \\
\relax  Messaging  &  XMPP (Prosody)  &  Federated encrypted chat  &  prosody.im   \\
\relax  Files  &  IPFS (Kubo)  &  Content-addressed file system  &  ipfs.tech   \\
\relax  Publishing  &  Hyphanet  &  Censorship-resistant anonymous publishing  &  hyphanet.org   \\
\relax  Voice  &  Asterisk  &  Private encrypted voice calls  &  asterisk.org   \\
\relax  Storage  &  ZFS (via Proxmox)  &  Self-healing RAID storage  &  Built into Proxmox   \\
\relax  Database  &  PostgreSQL  &  Reliable relational database  &  postgresql.org   \\
\relax  Cache  &  Redis  &  Fast in-memory cache  &  redis.io   \\
\relax  Automation  &  Ansible  &  Configure machines automatically  &  ansible.com   \\
\relax  IaC  &  OpenTofu  &  Provision infrastructure  &  opentofu.org   \\
\relax  Metrics  &  Prometheus + Grafana  &  Monitoring and dashboards  &  prometheus.io; grafana.com   \\
\relax  Logs  &  Loki  &  Centralized log aggregation  &  grafana.com\Slash{}oss\Slash{}loki   \\
\relax  SDR  &  SDR++ \Slash{} GNU Radio  &  Software defined radio  &  sdrpp.org; gnuradio.org   \\
\relax  Encryption  &  GPG \Slash{} Age  &  File and email encryption  &  gnupg.org; age-encryption.org   \\
\relax  Disk encryption  &  LUKS (via cryptsetup)  &  Full disk encryption  &  gitlab.com\Slash{}cryptsetup\Slash{}cryptsetup   \\
\relax  Password manager  &  Bitwarden (self-hosted) \Slash{} KeePassXC  &  Secure password storage  &  bitwarden.com; keepassxc.org   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip

\section{Troubleshooting: The Most Common Problems}

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|X|X|X|X|}
\hline
\relax  Problem  &  First Check  &  Second Check  &  Solution  &   &    \\
\hline
\relax  WireGuard peers not connecting  &  \texttt{wg show} — is the interface up?  &  Firewall: <code>nft list ruleset  &  grep 51820<\Slash{}code>  &  Ensure UDP 51820 is open; verify public keys match; check endpoints  &    \\
\relax  Matrix messages not federating  &  Check port 8448 is reachable from outside  &  <code>journalctl -u matrix-synapse  &  grep federation<\Slash{}code>  &  Verify DNS SRV records; check firewall; verify TLS certificate  &    \\
\relax  Tor not connecting  &  <code>journalctl -u tor  &  grep -i error<\Slash{}code>  &  Is Tor blocked? Try bridges  &  Configure obfs4 bridge in \texttt{/etc/tor/torrc}  &    \\
\relax  IPFS content not found  &  \texttt{ipfs swarm peers} — any peers?  &  <code>ipfs pin ls  &  grep [CID]<\Slash{}code>  &  Ensure at least one node has the CID pinned; check firewall port 4001  &    \\
\relax  Proxmox web UI unreachable  &  Can you SSH to the host?  &  \texttt{systemctl status pveproxy}  &  Restart pveproxy; check firewall allows port 8006 from admin IP  &   &    \\
\relax  PostgreSQL replication lag  &  \texttt{patronictl list}  &  Check replica disk I\Slash{}O: \texttt{iostat -x 1}  &  Increase wal\_sender\_timeout; ensure replica hardware is fast enough  &   &    \\
\relax  Service crashes repeatedly  &  \texttt{journalctl -u [service] --since "1 hour ago"}  &  Check OOM killer: <code>journalctl -k  &  grep -i killed<\Slash{}code>  &  If OOM: allocate more RAM or add limits to other containers  &    \\
\relax  Disk full  &  \texttt{df -h}  &  <code>du -sh \Slash{}*  &  sort -rh  &  head -20<\Slash{}code>  &  Identify large directories; clean old logs; ZFS: destroy old snapshots   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip

\section{Glossary}

\bigskip
\noindent
 \begin{minipage}[t]{\textwidth}
\begin{tabularx}{\textwidth}{|X|X|}
\hline
\relax  Term  &  Plain-language definition   \\
\hline
\relax  APRS  &  Automatic Packet Reporting System — a digital radio protocol for sending position and text messages without internet   \\
\relax  BATMAN-adv  &  A mesh networking protocol where every device is both a client and a router   \\
\relax  BGP  &  Border Gateway Protocol — the routing protocol that connects ISPs and countries to form the global internet   \\
\relax  cgroups  &  Linux control groups — limit how much CPU\Slash{}RAM a process or container can use   \\
\relax  CID  &  Content Identifier — a hash-based address used in IPFS to name files by their content rather than their location   \\
\relax  DHT  &  Distributed Hash Table — a decentralized lookup system spread across many nodes with no central directory   \\
\relax  DPI  &  Deep Packet Inspection — inspection of network traffic content (not just the destination) to detect and block specific protocols   \\
\relax  E2EE  &  End-to-End Encryption — messages are encrypted by the sender and can only be decrypted by the intended recipient   \\
\relax  Federation  &  Multiple independently-operated servers speaking the same protocol — like email but for chat   \\
\relax  HF  &  High Frequency (3–30 MHz) — shortwave radio bands that bounce off the ionosphere for global communication   \\
\relax  IPFS  &  InterPlanetary File System — a P2P file system that identifies files by their content hash rather than their location   \\
\relax  IQ sampling  &  A technique for capturing radio signals with two measurements 90° apart in phase, enabling full signal reconstruction in software   \\
\relax  Kademlia  &  The DHT algorithm used by IPFS and BitTorrent; uses XOR for distance measurement; scales to millions of nodes   \\
\relax  LoRa  &  Long Range — a radio modulation technique enabling low-power, long-range digital communications (2–40 km)   \\
\relax  LUKS  &  Linux Unified Key Setup — the standard for full-disk encryption on Linux   \\
\relax  Namespaces  &  Linux kernel feature that gives each container its own isolated view of the system (its own network, processes, filesystem)   \\
\relax  Onion service  &  A Tor-hidden server whose real IP address is never revealed; only accessible via a .onion address   \\
\relax  OpSec  &  Operational Security — practices to minimize information leakage through human behavior   \\
\relax  Overlay network  &  A virtual network built on top of an existing physical network with independent routing   \\
\relax  P2P  &  Peer-to-Peer — a network where every participant is both client and server; no central node   \\
\relax  Quorum  &  The minimum number of nodes that must agree before a distributed system can commit a change (usually majority)   \\
\relax  Raft  &  A consensus algorithm that elects a leader and requires a majority of nodes to acknowledge writes   \\
\relax  RPO  &  Recovery Point Objective — how much data loss is acceptable (measured in time)   \\
\relax  RTO  &  Recovery Time Objective — how long a service can be unavailable after a failure   \\
\relax  SDR  &  Software Defined Radio — radio hardware whose functions are implemented in software rather than dedicated circuits   \\
\relax  SSB  &  Single Sideband — an efficient voice radio mode used on HF for long-distance communication   \\
\relax  TLS  &  Transport Layer Security — the cryptographic protocol behind HTTPS; encrypts network connections   \\
\relax  VPN  &  Virtual Private Network — creates an encrypted tunnel between computers so traffic appears as noise to network observers   \\
\relax  VLAN  &  Virtual LAN — logically separates networks on the same physical switch infrastructure   \\
\relax  WireGuard  &  A modern, simple, fast VPN protocol using state-of-the-art cryptography   \\
\relax  XOR  &  Exclusive-Or — a bitwise operation used by Kademlia to measure “distance” between node IDs in a DHT   \\
\relax  Yggdrasil  &  A self-organizing, end-to-end encrypted network overlay using DHT-based routing   \\
\relax  ZFS  &  Zettabyte File System — a storage system with built-in checksums, RAID, compression, encryption, and instant snapshots   \\
\hline
\end{tabularx}
\end{minipage}
\bigskip

\chapter{Closing: The Philosophy of Resilience}


The technology in this book is not magic. It requires time, patience, and deliberate practice. Systems will break during setup. Configurations will be wrong the first time. Commands will fail. This is normal and expected. Every expert was once a beginner who was confused by the same things.


The most important principle is simple: \textbf{decentralize everything.}


\begin{itemize}
\item\relax 
Do not depend on a single chat application that a corporation can shut down — run your own.



\item\relax 
Do not depend on a single server that can be seized — distribute across many.



\item\relax 
Do not depend on the internet — build radio capability.



\item\relax 
Do not depend on any single person’s knowledge — document everything and train others.



\item\relax 
Do not depend on location-addressed files — use content-addressed storage so documents survive.



\item\relax 
Do not depend on a central authority for identity — use cryptographic keys that only you control.




\end{itemize}

Authoritarian systems derive their power from control of information and communication. Every system described in this book reduces that control by moving infrastructure to the edges — into the hands of ordinary people with ordinary hardware, running free software that anyone can read, audit, and verify.


The goal is not to be undetectable. That is nearly impossible for sustained operations. The goal is to be \textbf{resilient} — so that when one piece is taken down, the rest continues working, and rebuilding what was lost takes hours, not months.


Decentralized networks have no single throat to choke. That is the point.


This book covers exclusively open-source, publicly documented technologies used by journalists, researchers, emergency responders, and privacy advocates worldwide. Nothing in this book is secret. Everything here can be found in public documentation, academic papers, textbooks, and the documentation of the software projects described. Knowledge of how technology works is not a crime.


Stay safe. Stay connected. Keep building.









% begin final page

\clearpage


% if we are on an odd page, add another one, otherwise when imposing
% the page would be odd on an even one.
\ifthispageodd{\strut\thispagestyle{empty}\clearpage}{}


% new page for the colophon

\thispagestyle{empty}

\begin{center}

The Anarchist Library (Mirror)



\smallskip
Anti-Copyright



\bigskip
\includegraphics[width=0.25\textwidth]{logo-yu.pdf}
\bigskip

\end{center}

\strut

\vfill

\begin{center}


The Techno Anarchist

Resilient by Design

A Complete Guide to Decentralized, Private \& Censorship-Resistant Technology From First Principles to Running Infrastructure




\bigskip



   

       

       
         Based on the Distributed Networking \& SDR Homelab Handbook\forcelinebreak and the Decentralized Networking \& Peer-to-Peer Architecture Supplement\forcelinebreak  Open-source technologies only • No prior knowledge required • Complete with theory and practical application
       

       

       

       

       

   



\bigskip
\textbf{usa.anarchistlibraries.net}


\end{center}

% end final page with colophon


% end closing pages



\end{document}


% No format ID passed.



