diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..db09ee5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/result +/themes +/public diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..d55c645 --- /dev/null +++ b/config.toml @@ -0,0 +1,45 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# SPDX-License-Identifier: MPL-2.0 +base_url = "/" +title = "Avery Winters" +description = "Avery Winters' personal site and blog." +default_language = "en" +theme = "zerm" +compile_sass = true +minify_html = false +generate_feed = true +taxonomies = [{ name = "tags" }] +build_search_index = true + +[markdown] +highlight_code = true +highlight_theme = "gruvbox-dark" +external_links_no_follow = true +external_links_no_referrer = true +smart_punctuation = false + +[extra] +author = "Avery Winters" +show_author = false +show_categories = false +show_tags = true +theme_color = "blue" +show_menu_items = 5 +full_width = false +center = true +copyright = "Content and assets licensed CC BY-SA 4.0 unless otherwise noted." +logo_text = "Avery Winters" +main_menu = [ + { name = "about", url = "/about/" }, + { name = "mastodon", url = "https://mastodon.averywinters.org/@avery", external = true }, + { name = "git forge", url = "https://git.averywinters.org/", external = true }, + { name = "codeberg", url = "https://codeberg.org/averywinters", external = true }, + { name = "github", url = "https://github.com/averywinters", external = true }, +] +menu_more = "show more" +read_more = "read more" +read_other_posts = "read other posts" +enable_katex = true +disques = { enabled = false, short_name = "" } diff --git a/content/2023-09-14-security-infrastructure.md b/content/2023-09-14-security-infrastructure.md new file mode 100644 index 0000000..c16ccf5 --- /dev/null +++ b/content/2023-09-14-security-infrastructure.md @@ -0,0 +1,72 @@ ++++ +title = "Security & Infrastructure" +description = "An overview of all the infrastructure and services I host, and the security mindset behind it." +date = 2023-09-14 +[taxonomies] +tags=["selfhosting", "nix", "privacy", "security", "networks"] ++++ + +# Security & Infrastructure + +Everything on this domain is [self-hosted][0], from DNS to email and all web +services. I currently manage four servers: +- `amsterdam` and `dublin`: VMs running on a physical server I own and control +the physical security of. +- `berlin`: A Vultr VPS. +- `copenhagen`: A Linode VPS. + +`amsterdam` acts as the primary nameserver, controlling DNSSEC signing and is +thus the root of trust for the domain. It also runs the primary mail server and +most web services. + +`dublin` acts as a secondary nameserver and (soon) a backup email queue and +backup web server for this static site. + +Finally, `berlin` and `copenhagen` act as routers for `amsterdam` and `dublin` +respectively. Each has secondary static IPv4 and IPv6 addresses that are routed +over a tunnel to bypass NAT and hosting restrictions on my physical server. +Additionally, these VPSs also act as secondary nameservers in case my home +network is down. + +The goal with all of this is to have some basic redundancy, while keeping +sensitive keys and all personal data safely on my physical server. + +## DNSSEC +`amsterdam` holds a [combined signing key][13] for the zone. Dynamic updates +are allowed using [TSIG][1] keys on `amsterdam` and `dublin` to allow [ACME DNS-01 challenges][2] for issuing TLS certificates. + +## TLS/HTTPS +`dublin` and `amsterdam` hold a [Let's Encrypt][3] wildcard TLS certificate +for the domain, which is used to protect web services. The DNS zone contains a +[CAA][4] record specifying that only Let's Encrypt may issue certificates for +the domain, and only using ACME DNS-01 challenges. All TLS-capable services have TLSA records associated with them for [DANE-EE][5] support. +Finally, all web services use [HTTPS][6] records and [HSTS preload][7] headers +to advertise support for HTTPS. + +## Email +`amsterdam` holds [DKIM][8] keys for the domain, which is published in DNS +alongside [SPF][9] and [DMARC][10] records together protect against spoofing +the domain. [MTA-STS][11] and DANE-EE are used to advertise TLS support for +incoming mail. Outgoing mail requires that the receiving server support TLS. + +## WireGuard +All servers hold [WireGuard][14] keys for their end of the tunnels. The tunnel +being encrypted and authenticated isn't actually important for my purposes. This +could just as easily use another tunneling protocol like [GRE][12], but I find +WireGuard trivial to setup even if it adds some keys to manage. + +[0]: https://git.averywinters.org/avery/home +[1]: https://en.wikipedia.org/wiki/TSIG +[2]: https://letsencrypt.org/docs/challenge-types/#dns-01-challenge +[3]: https://letsencrypt.org +[4]: https://letsencrypt.org/docs/caa +[5]: https://en.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities +[6]: https://developer.mozilla.org/en-US/docs/Glossary/https_rr +[7]: https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security +[8]: https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail +[9]: https://en.wikipedia.org/wiki/Sender_Policy_Framework +[10]: https://en.wikipedia.org/wiki/DMARC +[11]: https://datatracker.ietf.org/doc/html/rfc8461 +[12]: https://en.wikipedia.org/wiki/Generic_Routing_Encapsulation +[13]: https://datatracker.ietf.org/doc/html/rfc6781 +[14]: https://www.wireguard.com diff --git a/content/_index.md b/content/_index.md new file mode 100644 index 0000000..8ad3ed8 --- /dev/null +++ b/content/_index.md @@ -0,0 +1,6 @@ ++++ +sort_by = "date" +transparent = true +paginate_by = 6 +insert_anchor_links = "right" ++++ diff --git a/content/pages/_index.md b/content/pages/_index.md new file mode 100644 index 0000000..800a244 --- /dev/null +++ b/content/pages/_index.md @@ -0,0 +1,3 @@ ++++ +render = false ++++ diff --git a/content/pages/about.md b/content/pages/about.md new file mode 100644 index 0000000..4b6b6b7 --- /dev/null +++ b/content/pages/about.md @@ -0,0 +1,22 @@ ++++ +title = "About Me" +path = "about" +date = 2023-09-14 ++++ + +| ![A closeup photo of a blue snowflake resting on a tree branch.][0] | +|:--:| +| *Photo taken by [Egor Kamelev][1] and dedicated into the public domain.* | + +Hello! I'm Avery Winters. I build software that gives people a reason to not +hate their computers as much. I care a lot about robustness, performance, and +preserving people's [#privacy](/tags/privacy) and freedom. + +I tend to post about [#rust](/tags/rust) 🦀, [#nix](/tags/nix) ❄, +[#floss](/tags/floss) 🧑‍💻, [#security](/tags/security) 🔒, +[#networks](/tags/networks) 🌐, [#selfhosting](/tags/selfhosting) 🖥️, +[#urbanism](/tags/urbanism) 🚲, [#leftism](/tags/leftism) 🌹, +[#anarchism](/tags/anarchism) 🏴, and [#christianity](/tags/christianity) ✝️. + +[0]: /img/profile.jpg +[1]: https://pxhere.com/en/photo/1562545 diff --git a/flake.lock b/flake.lock index 51ee8f8..637c260 100644 --- a/flake.lock +++ b/flake.lock @@ -1,8 +1,33 @@ { "nodes": { + "devshell": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "systems": [ + "systems" + ] + }, + "locked": { + "lastModified": 1694435990, + "narHash": "sha256-yLQPD2eZGepu3yvdwABXrR3GhAqWRWTj9rn3a4knYuk=", + "owner": "numtide", + "repo": "devshell", + "rev": "f6aec2e8b1cdddcab10ce7fc2eac66886e3deaad", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, "flake-utils": { "inputs": { - "systems": "systems" + "systems": [ + "systems" + ] }, "locked": { "lastModified": 1694529238, @@ -36,8 +61,11 @@ }, "root": { "inputs": { + "devshell": "devshell", "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs", + "systems": "systems", + "zerm": "zerm" } }, "systems": { @@ -54,6 +82,22 @@ "repo": "default", "type": "github" } + }, + "zerm": { + "flake": false, + "locked": { + "lastModified": 1655175694, + "narHash": "sha256-FhcBVJtRuQp59hI8vRnobp2vXCXbtE0l8t7EDGeXyyA=", + "owner": "ejmg", + "repo": "zerm", + "rev": "c9c3524cbd0cb90f91158cd33a113da464d32e6b", + "type": "github" + }, + "original": { + "owner": "ejmg", + "repo": "zerm", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 35bc70f..898d552 100644 --- a/flake.nix +++ b/flake.nix @@ -4,16 +4,59 @@ # SPDX-License-Identifier: MPL-2.0 { inputs = { - flake-utils.url = "github:numtide/flake-utils"; + devshell = { + url = "github:numtide/devshell"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.systems.follows = "systems"; + }; + flake-utils = { + url = "github:numtide/flake-utils"; + inputs.systems.follows = "systems"; + }; nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; + systems.url = "github:nix-systems/default"; + zerm = { + url = "github:ejmg/zerm"; + flake = false; + }; }; outputs = { + devshell, flake-utils, nixpkgs, + zerm, ... }: (flake-utils.lib.eachDefaultSystem (system: let - pkgs = import nixpkgs {inherit system;}; + pkgs = import nixpkgs { + inherit system; + overlays = [devshell.overlays.default]; + }; in { formatter = pkgs.alejandra; + devShells.default = let + commands = [ + {package = pkgs.zola;} + ]; + startupScript = '' + mkdir -p themes + ln -snf "${zerm}" "themes/zerm" + ''; + in + pkgs.devshell.mkShell { + inherit commands; + devshell.startup.themes.text = startupScript; + }; + packages.default = pkgs.stdenv.mkDerivation { + pname = "averywinters.org"; + version = "1.0.0"; + src = ./.; + nativeBuildInputs = [pkgs.zola]; + configurePhase = '' + mkdir -p themes + ln -snf "${zerm}" "themes/zerm" + ''; + buildPhase = "zola build"; + installPhase = "cp -r public $out"; + }; })); } diff --git a/static/img/profile.jpg b/static/img/profile.jpg new file mode 100644 index 0000000..c6eac16 Binary files /dev/null and b/static/img/profile.jpg differ diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..5cfe341 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,5 @@ +{% extends "zerm/templates/index.html" %} +{%- block general_meta -%} + {{ head::general_meta() }} + +{%- endblock general_meta -%}