diff options
| author | Xe Iaso <me@xeiaso.net> | 2023-10-11 07:29:21 -0400 |
|---|---|---|
| committer | Xe Iaso <me@xeiaso.net> | 2023-10-11 07:29:21 -0400 |
| commit | 49a10972906eb47e5add7267dc193e2556d93a36 (patch) | |
| tree | cd05c30c38a93ff88b5dc2bcbde904249c3f9aba /lume | |
| parent | 842674229bde83bb97384989d09c4abb2936b4ad (diff) | |
| download | xesite-49a10972906eb47e5add7267dc193e2556d93a36.tar.xz xesite-49a10972906eb47e5add7267dc193e2556d93a36.zip | |
lume/blog: import a talk that I am proud of
Signed-off-by: Xe Iaso <me@xeiaso.net>
Diffstat (limited to 'lume')
| -rw-r--r-- | lume/_config.ts | 5 | ||||
| -rw-r--r-- | lume/src/_components/BlockQuote.jsx | 7 | ||||
| -rw-r--r-- | lume/src/_components/Figure.tsx | 15 | ||||
| -rw-r--r-- | lume/src/blog/docker-mod-tailscale.mdx | 346 | ||||
| -rw-r--r-- | lume/src/blog/tailscale-configuring-emacs-mdx.mdx | 104 | ||||
| -rw-r--r-- | lume/src/blog/tailscale-headscale-funnel.md | 19 | ||||
| -rw-r--r-- | lume/src/blog/tailscale-headscale-funnel.mdx | 329 | ||||
| -rw-r--r-- | lume/src/blog/tailscale-nas-101.md | 4 | ||||
| -rw-r--r-- | lume/src/blog/tailscale-social-proximity-networks.md | 5 | ||||
| -rw-r--r-- | lume/src/blog/tailscale-steam-deck.mdx | 4 | ||||
| -rw-r--r-- | lume/src/styles.css | 9 | ||||
| -rw-r--r-- | lume/src/talks/subtle-magic-tsnet.mdx | 452 |
12 files changed, 1267 insertions, 32 deletions
diff --git a/lume/_config.ts b/lume/_config.ts index 333cd9e..4d91ff2 100644 --- a/lume/_config.ts +++ b/lume/_config.ts @@ -11,6 +11,8 @@ import postcss from "lume/plugins/postcss.ts"; import tailwindOptions from "./tailwind.config.js"; +import BlockQuote from "./src/_components/BlockQuote.jsx"; +import Figure from "./src/_components/Figure.tsx"; import XeblogConv from "./src/_components/XeblogConv.tsx"; import XeblogHero from "./src/_components/XeblogHero.tsx"; import XeblogPicture from "./src/_components/XeblogPicture.tsx"; @@ -52,6 +54,9 @@ site.use(feed({ })); site.use(mdx({ components: { + "BlockQuote": BlockQuote, + "Figure": Figure, + "Image": Figure, "XeblogConv": XeblogConv, "XesiteConv": XeblogConv, "XeblogHero": XeblogHero, diff --git a/lume/src/_components/BlockQuote.jsx b/lume/src/_components/BlockQuote.jsx new file mode 100644 index 0000000..bf15dd5 --- /dev/null +++ b/lume/src/_components/BlockQuote.jsx @@ -0,0 +1,7 @@ +export default function BlockQuote({ children }) { + return ( + <div className="mx-auto mt-4 mb-2 rounded-lg bg-bg-2 p-4 dark:bg-bgDark-2 md:max-w-lg xe-dont-newline"> + > {children} + </div> + ); +};
\ No newline at end of file diff --git a/lume/src/_components/Figure.tsx b/lume/src/_components/Figure.tsx new file mode 100644 index 0000000..99dc4e2 --- /dev/null +++ b/lume/src/_components/Figure.tsx @@ -0,0 +1,15 @@ +export interface FigureProps { + className?: string; + path: string; + desc?: string; + alt?: string; +} + +export default function Figure({ className, path, alt, desc = alt}: FigureProps) { + return ( + <figure className={`max-w-3xl mx-auto ${className}`}> + <img src={`https://cdn.xeiaso.net/file/christine-static/${path}`} alt={desc} /> + {desc && <figcaption>{desc}</figcaption>} + </figure> + ); +} diff --git a/lume/src/blog/docker-mod-tailscale.mdx b/lume/src/blog/docker-mod-tailscale.mdx new file mode 100644 index 0000000..3f66f67 --- /dev/null +++ b/lume/src/blog/docker-mod-tailscale.mdx @@ -0,0 +1,346 @@ +--- +title: 'Introducing the Tailscale Universal Docker Mod' +date: 2023-04-14 +tags: + - docker + - philosophy +hero: + file: shipyard-vibes + ai: Ligne Claire v1.5 + prompt: flat color, shipyard, containers, mountains, no humans, space needle +--- + +<div className="text-xl"> + This post was written while I worked for Tailscale. It is archived here for posterity. +</div> + +Imagine a world where you could add applications to your tailnet the same way you add machines to it. This would mean that `http://wiki` would go to your internal wiki, `http://code` would take you to an IDE, and `http://chat` would take you to your internal chat server. This is the world that Tailscale lets you create, but historically the details on how you would actually do this are left as an exercise for the reader. + +Today, we're introducing a new way to add Tailscale to your Docker containers: our brand new [universal Docker mod](https://github.com/linuxserver/docker-mods/blob/master/README.md). This lets you add Tailscale to any Docker container based on [linuxserver.io](https://linuxserver.io) images. This lets you have applications join your tailnet just as easily as machines can. You can set up a wiki on `http://wiki`, an IDE at `http://code`, and a chat server at `http://chat` and have them all be accessible over your tailnet. You can even use this to expose your internal applications to the public internet with [Funnel](https://tailscale.com/kb/1112/funnel/). + +<XeblogConv name="Cadey" mood="enby"> + You can even use this to SSH into containers! +</XeblogConv> +<XesiteConv name="Aoi" mood="coffee"> + You can _what_ into a container? +</XesiteConv> +<XeblogConv name="Cadey" mood="enby"> + Yep! [Tailscale SSH](https://tailscale.com/kb/1193/ssh/) lets you SSH into containers when you enable the `TAILSCALE_USE_SSH` setting and [permit access in the ACLs](https://tailscale.com/kb/1193/tailscale-ssh/#ensure-tailscale-ssh-is-permitted-in-acls). This is a great way to get into a container without having to SSH into the docker host and run `docker exec -it <container> bash`. +</XeblogConv> + +To add this to your existing Docker containers with linuxserver.io images, add the following environment variables to your docker-compose.yml file: + +```yaml +- DOCKER_MODS=ghcr.io/tailscale-dev/docker-mod:main +# tailscale configuration + +# make sure this is persisted in a volume +- TAILSCALE_STATE_DIR=/var/lib/tailscale +- TAILSCALE_SERVE_MODE=https +- TAILSCALE_SERVE_PORT=80 +- TAILSCALE_USE_SSH=1 +- TAILSCALE_HOSTNAME=wiki + +## uncomment to enable funnel +## remember that if you do, it's exposed to the internet, so be careful! +#- TAILSCALE_FUNNEL=on + +# replace this with your authkey from the admin panel +- TAILSCALE_AUTHKEY=tskey-auth-hunter2CNTRL-hunter2hunter2 +``` + +This will add Tailscale to your container so that you can access it over your tailnet. If you run `docker compose up -d` with the authkey changed out for [a valid authkey](https://login.tailscale.com/admin/settings/keys), you'll be able to access your apps over Tailscale. + +## Docker and Docker mods + +Docker allows you to create snapshots of operating system installs with a given state, such as "having the [Go](https://go.dev) compiler available" or "install this program and all its dependencies" and distribute those preconfigured images on the Internet. When you consume the same Docker image at two time intervals T0 and T1, you get the same image with the same code, just as you expect. + +When a Docker container is run, it usually runs on top of an ephemeral filesystem that gets destroyed when the container is stopped. This means that restarting the container will reset it back to the state that was there when the image was created. This is normally convenient when working on applications that make temporary changes to the filesystem, such as an image converter that uses temporary files to do the conversion logic. + +This is less convenient when you want to run things like database servers in Docker. However, most of the time when you do things that need persistent state, that persistent state is usually limited to a single file or directory. Docker provides external persistent state with [volumes](https://docs.docker.com/storage/volumes/). They're basically directories that are plunked into the container at runtime, but it maintains the state between container runs. This is great for things like databases because you wouldn't want to lose all your data when you restart the container. + +<Image + className="mx-auto" + path="blog/2023/universal-docker-mod/docker-normal.svg" + alt="The expected hierarchies of Docker containers and their statefulness" +/> + +So, from here we can create a hierarchy for docker and statefulness. You expect docker containers to have state for _data_, and you also expect the docker container to be running the same code every time you run the same image. You don't expect anything else to be running, everything is deterministic at T0, T1, or TN. + +<XeblogConv name="Cadey" mood="enby"> + This is a valid hierarchy because it's what you expect from docker. You expect the same code to + run every time you run the same image. +</XeblogConv> + +### What is humor? + +Humor is a complicated concept that is almost universal throughout human cultures. It's a way of conveying concepts like absurdity, irony, the absurdity of irony, and normally frustrating things in ways that aren't quite as much of a downer. It's really about being able to communicate subtle things like common errors that everyone makes when learning things (such as English and its rule of all the rules having exceptions, even for the exceptions). It's also a tool that you can use to help describe the abstract and nonphysical things like emotions, feelings, ideas, the human condition, and how Kubernetes works. + +<XeblogConv name="Cadey" mood="enby"> + Humor is also really hard to convey properly in a written medium. This is even more difficult when + the humor is about technology, which is usually hard to understand in the first place. I'm going + to try to explain the humor in this article with these asides so that y'all can follow along, but + if you already get why this is funny it may ruin the joke for you. Sorry! +</XeblogConv> + +In his famous presentation [Reverse emulating the NES](https://youtu.be/ar9WRwCiSr0), fellow philosopher in arms [tom7](http://tom7.org/) introduced the idea of a type of humor called "invalid hierarchies". In this he does rather abusrd things to an NES using a custom circuit board and a raspbery pi to allow him to (among other things) run an SNES emulator on the NES. This video is quite possibly one of my favorite technical communication videos and is a huge influence to how I write humorous things for this blog. + +<XeblogConv name="Cadey" mood="enby"> + This creates an invalid hierarchy because you expect the NES to only run 8-bit NES games, but not + 16-bit SNES games. This is funny. If you've never seen that video before, it's well worth a watch. + <br /> + Another example of an invalid hierarchy is my April Fool's Day post [Using Tailscale without using + Tailscale](https://tailscale.dev/blog/headscale-funnel). You'd expect to have to use Tailscale if + you want to use Tailscale, but "using Tailscale without using Tailscale" creates an invalid + hierarchy in the mind of the reader. This is also funny. +</XeblogConv> + +<Image + className="mx-auto" + path="blog/2023/universal-docker-mod/nes-snes.svg" + alt="The expected hierarchies of NES and SNES consoles and their games" +/> + +### Docker mods + +Docker mods let you install extra packages and services into containers at runtime. If the `ONBUILD` hook lets you run a series of commands when an image is built, you can think of docker mods as a missing `ONRUN` hook that lets you customize an image at runtime. + +<Image + className="mx-auto" + path="blog/2023/universal-docker-mod/docker-mod.svg" + alt="How Docker mods change the statefulness of a container" +/> + +<XeblogConv name="Cadey" mood="enby"> + This creates an invalid hierarchy because we think about the code in a container being + deterministic between invocations and this allows you to make something _nondeterministic_. This + is funny. +</XeblogConv> + +### Docker mods and s6 + +At a high level, a docker mod is a series of files that add additional instructions to the start phase of a docker container. It works because the [linuxserver.io](https://www.linuxserver.io/) containers preinstall [s6](https://skarnet.org/software/s6/) via [s6-overlay](https://github.com/just-containers/s6-overlay) and then start it in the background to manage the lifecycle of services in the container. + +<XeblogConv name="Cadey" mood="enby"> + This is also funny because usually Docker containers aren't supposed to have multiple processes + running in them for simplicity, but it turns out that when you want to do things like put your + wiki seamlessly on your tailnet, you want to have multiple processes running. This is another + invalid hierarchy because you expect the container to only have one process running, but it has + multiple with a service manager, just like the host OS. +</XeblogConv> + +When I made the docker mod, I had to create a few s6 services to help it run: + +- One to set a list of packages that Tailscale needs to run ([jq](https://stedolan.github.io/jq/) to process some data from the packages server, and [iptables](https://linux.die.net/man/8/iptables) to configure the firewall inside the container for Tailscale to run in a [TUN](https://en.wikipedia.org/wiki/TUN/TAP) device). +- One to download Tailscale to the container. +- One to start the Tailscale node agent `tailscaled`. +- One to authenticate you to the tailnet with [`tailscale up`](https://tailscale.com/kb/1241/tailscale-up/) and set other settings like [`tailscale serve`](https://tailscale.com/kb/1242/tailscale-serve/). + +<XeblogConv name="Cadey" mood="enby"> + This is also hilarious because this roughly mirrors the process that you have to do on your host + OS to get Tailscale running. This is another layer of invalid hierarchy because you expect + containers to ship with all the software they need, but here is this container that needs to + download software at runtime. This is funny because it's like a container that needs to download + software at runtime, just like your host OS. As above, so below, eh? +</XeblogConv> + +Each of these is connected together like this (arrows indicate dependencies): + +<Image + className="mx-auto" + path="blog/2023/universal-docker-mod/s6.svg" + alt="The s6 dependency web" +/> + +<XeblogConv name="Cadey" mood="enby"> + If you've ever worked deeply with the Heroku ecosystem, you can think about Docker mods as akin to + all of the hilarous hacks you can do with buildpacks at dyno boot time. +</XeblogConv> + +## Configuration + +The Docker mod exposes a bunch of environment variables that you can use to configure it. You can see the full list of environment variables in the [documentation](https://github.com/tailscale-dev/docker-mod), but here are the important ones: + +| Environment Variable | Description | Example | +| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :--------------------------------------- | +| `DOCKER_MODS` | The list of additional mods to layer on top of the running container, separated by pipes. | `ghcr.io/tailscale-dev/docker-mod:main` | +| `TAILSCALE_STATE_DIR` | The directory where the Tailscale state will be stored, this should be pointed to a Docker volume. If it is not, then the node will set itself as ephemeral, making the node disappear from your tailnet when the container exits. | `/var/lib/tailscale` | +| `TAILSCALE_AUTHKEY` | The authkey for your tailnet. You can create one in the [admin panel](https://login.tailscale.com/admin/settings/keys). See [here](https://tailscale.com/kb/1085/auth-keys/) for more information about authkeys and what you can do with them. | `tskey-auth-hunter2CNTRL-hunter2hunter2` | +| `TAILSCALE_HOSTNAME` | The hostname that you want to set for the container. If you don't set this, the hostname of the node on your tailnet will be a bunch of random hexadecimal numbers, which many humans find hard to remember. | `wiki` | +| `TAILSCALE_USE_SSH` | Set this to `1` to enable SSH access to the container. | `1` | +| `TAILSCALE_SERVE_PORT` | The port number that you want to expose on your tailnet. This will be the port of your DokuWiki, Transmission, or other container. | `80` | +| `TAILSCALE_SERVE_MODE` | The mode you want to run Tailscale serving in. This should be `https` in most cases, but there may be times when you need to enable `tls-terminated-tcp` to deal with some weird edge cases like HTTP long-poll connections. See [here](https://tailscale.com/kb/1242/tailscale-serve/) for more information. | `https` | +| `TAILSCALE_FUNNEL` | Set this to `true`, `1`, or `t` to enable [funnel](https://tailscale.com/kb/1243/funnel/). For more information about the accepted syntax, please read the [strconv.ParseBool documentation](https://pkg.go.dev/strconv#ParseBool) in the Go standard library. | `on` | + +Something important to keep in mind is that you really should set up a separate volume for Tailscale state. Here is how to do that with the docker commandline: + +```sh +docker volume create dokuwiki-tailscale +``` + +Then you can mount it into a container by using the volume name instead of a host path: + +```bash +docker run \ + ... \ + -v dokuwiki-tailscale:/var/lib/tailscale \ + ... +``` + +If you want to use kernel networking mode, you will need to add the `NET_ADMIN` and `NET_RAW` capabilities to the container, as well as pass the [`/dev/net/tun`](https://www.kernel.org/doc/Documentation/networking/tuntap.txt) device into the container. Here is an example of how to do that with the docker commandline: + +```bash +docker run \ + ... \ + --cap-add=NET_ADMIN \ + --cap-add=NET_RAW \ + --device=/dev/net/tun \ + ... +``` + +In a `compose.yaml` file, it will look like this: + +```yaml +version: '2.1' +services: + dokuwiki: + image: lscr.io/linuxserver/dokuwiki:latest + volumes: + - /dev/net/tun:/dev/net/tun + cap_add: + - NET_ADMIN + - NET_RAW + # ... +``` + +This can be useful when you are running applications on your tailnet _without_ [tailscale serve](https://tailscale.com/kb/1242/tailscale-serve/), and you want the underlying service to know the exact remote IP address (such as when running a Minecraft server). + +## Fun things you can do + +Normally when I write these articles, I tend to give you one functional example so that you can fill in the blanks here. This time, I want to give you a few functional and genuninely useful examples so that you can get started with our Docker mod right away. + +If you want to test this with a simple command-line shell, you can run this docker command to create a volume for Tailscale state, and then run a container with the Docker mod installed: + +```bash +docker volume create trap-sun-state +``` + +<XeblogConv name="Cadey" mood="enby"> + `trap-sun` is the name of the container that we will be running. You can name it whatever you + want, but you should use the same name in both your volume and your container. I'm setting the + name here in case you get stuck and need to arbitrarily kill the container with `docker kill + trap-sun`. +</XeblogConv> + +```bash +docker run \ + --rm \ + -v trap-sun-state:/var/lib/tailscale \ + -e TAILSCALE_STATE_DIR=/var/lib/tailscale \ + -e TAILSCALE_SERVE_PORT=3000 \ + -e TAILSCALE_SERVE_MODE=https \ + -e TAILSCALE_FUNNEL=on \ + -e TAILSCALE_USE_SSH=1 \ + -e TAILSCALE_HOSTNAME=trap-sun \ + -e TAILSCALE_AUTHKEY=tskey-auth-hunter2CNTRL-hunter2hunter2 \ + -e DOCKER_MODS=ghcr.io/tailscale-dev/docker-mod:main \ + --name trap-sun \ + -it \ + --cap-add=NET_ADMIN \ + --cap-add=NET_RAW \ + -v /dev/net/tun:/dev/net/tun \ + lsiobase/alpine:3.17 \ + sh +``` + +<XeblogConv name="Cadey" mood="enby"> + You can also base your Docker images on the `lscr.io/linuxserver/baseimage-alpine:3.17` image, + which is a minimal [Alpine Linux](https://alpinelinux.org) with Docker mod support. This can be + used to adapt your existing containers into nodes on your tailnet. You can also use + [Ubuntu](https://ubuntu.com) with `lscr.io/linuxserver/baseimage-ubuntu:jammy` as the base image. + The cloud's the limit! +</XeblogConv> + +### DokuWiki + +If you want to set up a wiki for your tailnet with [DokuWiki](https://www.dokuwiki.org/dokuwiki), you can use this Docker compose file: + +```yaml +# docker-compose.yaml +version: '2.1' +services: + dokuwiki: + image: lscr.io/linuxserver/dokuwiki:latest + container_name: dokuwiki + environment: + - PUID=1000 + - PGID=1000 + - TZ=Etc/UTC + - DOCKER_MODS=ghcr.io/tailscale-dev/docker-mod:main + # tailscale information + - TAILSCALE_STATE_DIR=/var/lib/tailscale + - TAILSCALE_SERVE_PORT=80 + - TAILSCALE_SERVE_MODE=https + ## uncomment to enable funnel, may be a bad idea for some use cases + #- TAILSCALE_FUNNEL=on + - TAILSCALE_USE_SSH=1 + - TAILSCALE_HOSTNAME=wiki + - TAILSCALE_AUTHKEY=tskey-auth-hunter2CNTRL-hunter2hunter2 + + volumes: + - dokuwiki-data:/config + - dokuwiki-tailscale:/var/lib/tailscale + restart: unless-stopped + +volumes: + dokuwiki-data: + dokuwiki-tailscale: +``` + +Then use `docker compose up -d` to start the DokuWiki container with Tailscale grafted in. You can then access your DokuWiki instance at `https://wiki.yourtailnet.ts.net`. You will want to do the setup wizard, and then you can start using your own private wiki! + +### Your private cloud development environment with code-server + +Want to have all the fun of [GitHub Codespaces](https://docs.github.com/en/codespaces/overview) without having to use GitHub's servers for development? Set up your own private cloud with [code-server](https://github.com/coder/code-server) and Tailscale! + +```yaml +version: '2.1' +services: + code-server: + image: lscr.io/linuxserver/code-server:latest + container_name: code-server + environment: + - PUID=1000 + - PGID=1000 + - TZ=Etc/UTC + - PASSWORD=hunter2 + - PROXY_DOMAIN=code.shark-harmonic.ts.net + - DOCKER_MODS=ghcr.io/tailscale-dev/docker-mod:main|ghcr.io/linuxserver/mods:code-server-nodejs|ghcr.io/linuxserver/mods:code-server-npmglobal + # tailscale information + - TAILSCALE_STATE_DIR=/var/lib/tailscale + - TAILSCALE_SERVE_PORT=8443 + - TAILSCALE_SERVE_MODE=tls-terminated-tcp + - TAILSCALE_USE_SSH=1 + - TAILSCALE_HOSTNAME=code + - TAILSCALE_AUTHKEY=tskey-auth-hunter2CNTRL-hunter2hunter2 + volumes: + - code-server-data:/config + - code-server-tailscale:/var/lib/tailscale + restart: unless-stopped + +volumes: + code-server-data: + code-server-tailscale: +``` + +Then use `docker compose up -d` to start the code-server container with Tailscale grafted in. You can then access your code-server instance at `https://code.shark-harmonic.ts.net`. You may want to change the password from [`hunter2`](http://bash.org/?244321) to something more secure. + +code-server also has support for cloning repositories from GitHub directly, so with this you can get started hacking on a project on one machine, then seamlessly pick up where you left off on another! You can start hacking at something in your office and then walk over to the local Tim Horton's to finish it up! + +--- + +There's a bunch of other containers in the [linuxserver.io fleet](https://fleet.linuxserver.io), you can use Tailscale with those as well. You can also check out [Awesome-LSIO](https://docs.linuxserver.io/general/awesome-lsio) for more ideas! + +At Tailscale, we want to recreate the Internet around the idea of small, trusted networks with your friends, family, and coworkers. When you set up applications on your tailnet like this, you can slowly start to use your own private infrastructure instead of relying on the public Internet. This is a great way to start using Tailscale, and we hope that you will find this Docker mod useful. + +If you have any questions, feel free to reach out to us on [Twitter](https://twitter.com/tailscale) or [the Fediverse](https://hachyderm.io/@tailscale). We are always happy to help! diff --git a/lume/src/blog/tailscale-configuring-emacs-mdx.mdx b/lume/src/blog/tailscale-configuring-emacs-mdx.mdx index 40677d5..6b59c83 100644 --- a/lume/src/blog/tailscale-configuring-emacs-mdx.mdx +++ b/lume/src/blog/tailscale-configuring-emacs-mdx.mdx @@ -1,18 +1,98 @@ --- title: "Configuring Emacs for MDX files" date: 2023-02-03 -redirect_to: https://tailscale.dev/blog/configuring-emacs-mdx +hero: + ai: Waifu Diffusion v1.4 + file: fantasy-landscape + prompt: masterpiece, digital art, watercolor, landscape, badlands, mountains --- -<XeblogConv name="Mimi" mood="happy"> - The article Configuring Emacs for MDX files on tailscale.dev is a blog post by - Xe, a Developer Advocate at Tailscale. It explains how Xe uses Emacs to edit - posts on the blog, which uses MDX instead of normal Markdown. MDX is a format - that combines Markdown with JSX, a syntax extension for JavaScript. The - article shows how to use directory-local variables in Emacs to change the - major mode for .mdx files to markdown-mode, and how to enable auto-formatting - with prettier on save. The article also provides some examples of other - directory-local variables that can be used to customize Emacs for different - modes and files. The article is intended for Emacs users who want to edit MDX - files or use directory-local variables for other purposes. +<div className="text-xl"> + This post was written while I worked for Tailscale. It is archived here for posterity. +</div> + +I'm an [Emacs](https://www.gnu.org/software/emacs/) user and I have +been for the last decade. I use emacs for _everything_ from code, to +posts on this blog, even down to my daily TODO list with [Org +Mode](https://orgmode.org/). Naturally, I want to also use emacs to +edit posts on this blog. The only problem is that the blog uses +[MDX](https://mdxjs.com/) instead of normal Markdown. There isn't an +Emacs major mode for MDX and the [ticket for editor support in MDX was +closed](https://github.com/mdx-js/mdx/issues/119). This should mean that I'm out of luck and must architect a new major mode for Emacs. + +However, this is Emacs. You have godlike power to do anything we want +here. MDX is just Markdown with JSX, and there's [already a widely +used major mode for Markdown named +`markdown-mode`](https://melpa.org/#/markdown-mode). JSX is close +enough to HTML that realistically we don't have to care about the +details, especially in an environment where the important JSX +components are already imported into the document scope for us. + +You can use all of this information to _bodge_ MDX support into Emacs +by using [directory-local +variables](https://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html). + +Directory-local variables live in `.dir-locals.el` and will apply to +any file in the same folder as the `.dir-locals.el` file _and all of +its subfolders_. If you stick a `.dir-locals.el` file at the top level +of a project, it will apply for all the files in the project. + +You can add MDX support to Emacs by changing the +[`auto-mode-alist`](https://www.emacswiki.org/emacs/AutoModeAlist) +variable to change which major mode Emacs uses based on the filetype: + +```lisp +;;; Directory Local Variables +;;; For more information see (info "(emacs) Directory Variables") + +((auto-mode-alist . (("\\.mdx\\'" . markdown-mode)))) +``` + +This will make every `.mdx` file load in markdown-mode, allowing you +to edit files like normal. It looks a bit horrible with only one +example, but the basic schema is that it's an association list (read: +hashtable) that contains variable definitions. If you also wanted to +make `markdown-mode` wrap files at 80 characters and `typescript-mode` +use two spaces for indent, you would do something like this: + +```lisp +;;; Directory Local Variables +;;; For more information see (info "(emacs) Directory Variables") + +((auto-mode-alist . (("\\.mdx\\'" . markdown-mode))) + (markdown-mode . ((fill-column . 80))) + (typescript-mode . ((typescript-indent-level . 2)))) +``` + +Sometimes you need to do a bit more though. This lets you set +variables for buffers, but it doesn't let you _execute code_ in +buffers. The CI configuration for this repo also needs us to make sure +our MDX documents are formatted correctly, and we use +[prettier](https://prettier.io/) to take care of all of that for us. + +Emacs lets you set the variable name `eval` to a block of lisp code to +run when loading buffers with that major mode. This lets you do things +like this to have `markdown-mode` auto-format files on save: + +```lisp +;;; Directory Local Variables +;;; For more information see (info "(emacs) Directory Variables") + +((auto-mode-alist . (("\\.mdx\\'" . markdown-mode))) + (markdown-mode . ((fill-column . 80) + (eval . (prettier-js-mode 1)))) + (typescript-mode . ((typescript-indent-level . 2)))) +``` + +This will make Emacs prompt you if you really want to do this every +time you load the file, but you can squelch this by using the `!` key. + +<XeblogConv name="Cadey" mood="enby"> + Make sure you know what the code is doing before you just blindly hit "yes"! </XeblogConv> + +This is all you need to get MDX working in Emacs. If you want to see +more, look at the +[`.dir-locals.el`](https://github.com/tailscale-dev/tailscale-dev/blob/main/.dir-locals.el) +in the [tailscale-dev](https://github.com/tailscale-dev/tailscale-dev) +repo. diff --git a/lume/src/blog/tailscale-headscale-funnel.md b/lume/src/blog/tailscale-headscale-funnel.md deleted file mode 100644 index 1aa34f8..0000000 --- a/lume/src/blog/tailscale-headscale-funnel.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: "Using Tailscale without using Tailscale" -date: 2023-04-01 -redirect_to: https://tailscale.dev/blog/headscale-funnel ---- - -I’m always amazed by the power of technology and the creativity of people who use it. Today I want to share with you a project that I did for fun and learning. It’s about how to use Tailscale Funnel to host a Headscale server from behind NAT. Sounds crazy, right? Let me explain. - -Tailscale Funnel is a tool that lets you share a web service on your private network with the public internet. It’s like having your own personal cloud without the hassle of setting up servers and domains. Headscale is a tool that lets you create your own Tailscale control plane. It’s like having your own private VPN without relying on a third-party service. - -Now, what if you could combine these two tools and create a network that uses Tailscale without using Tailscale? That’s exactly what I did. I used waifud, NixOS, and Funnel to create a virtual machine that runs Headscale and exposes it to the internet. Then I used Funnel to connect other devices to this network and enjoy the benefits of Tailscale. - -Why did I do this? Because I love learning new things and challenging myself. Because I believe in the power of open source and decentralized solutions. Because I wanted to have some fun and make some jokes along the way. - -This project taught me a lot about networking, security, and automation. It also showed me how much potential there is in tools like Tailscale and Headscale. And it made me laugh at the absurdity of using Tailscale without using Tailscale. - -If you’re curious about how I did this, you can check out my blog post where I explain everything in detail. It’s not a serious tutorial, but rather a playful experiment. - -I hope this post inspires you to try new things and have fun with technology. Remember, nothing is impossible if you put your mind to it. And don’t forget to laugh at yourself sometimes. diff --git a/lume/src/blog/tailscale-headscale-funnel.mdx b/lume/src/blog/tailscale-headscale-funnel.mdx new file mode 100644 index 0000000..53c5667 --- /dev/null +++ b/lume/src/blog/tailscale-headscale-funnel.mdx @@ -0,0 +1,329 @@ +--- +title: "Using Tailscale without using Tailscale" +date: 2023-04-01 +hero: + ai: Waifu Diffusion v1.4 + file: serene-jogging + prompt: 1girl, green hair, green eyes, jogging, countryside, summer, blue sky, long hair, yoga pants, hoodie, barn, watercolor, peaceful, river, portrait, looking at distance, highly detailed, serene +--- + +<div className="text-xl"> + This post was written while I worked for Tailscale. It is archived here for posterity. +</div> + +As a philosopher, I find it useful to keep up on the latest trends in technology; especially given how much that technology seems to shape our daily lives as of late. One of the premier websites with which I use to do this is a site known as Hacker News. My friends and coworkers worry about how I use this website, because the takes on it can be...special, and I tend to view it as a bit of a surrealist comedy. However, my dear philosopher friend xeonmc asked a question that served as a fount of inspiration. They asked: + +<BlockQuote>Is it possible to use [Funnel] to host a Headscale server from behind NAT?</BlockQuote> + +<XesiteConv name="Aoi" mood="wut"> + Wait, what? Is that person asking you how to use Tailscale in a way that makes + you avoid using Tailscale? That's like asking how to use a car without using a + car. +</XesiteConv> + +Oh yes, [my dear fox](https://xeiaso.net/characters#aoi), it is. And today I am going to show you how you would create such an accursed spectacle. Buckle up, because this is going to be a wild ride. + +[Headscale](https://github.com/juanfont/headscale) is a self-hostable version of the Tailscale control plane. It's a great project, and it's quite remarkable what they've been able to accomplish through sheer reverse engineering fueled by the boredom that came up at the start of the pandemic. You can set up a Headscale server and completely bypass the need to use the Tailscale SaaS offering. This enables people who don't want to or can't use the SaaS control plane to use Tailscale. + +However, in order to host this you need to expose something to the internet. If you don't do this, this creates a catch-22 situation where your clients won't be on the network and then will try to access your thing on the network and it just will not work at all. This is where Funnel comes in. + +[Funnel](https://tailscale.com/kb/1223/tailscale-funnel/) is a feature of Tailscale that allows you to expose a service on your network to the internet. This is the missing part of this equation, and what will allow us to use Tailscale (the service to connect devices together) without using Tailscale (the SaaS control plane) for the rest of the network. + +Here are the things you need for this tutorial: + +- A Tailscale account on the [SaaS control plane](https://login.tailscale.com) (you can use some throwaway gmail address for this). +- Somewhere to run virtual machines (I use something I made called [waifud](https://github.com/Xe/waifud)). +- Machines to join to your headscalenet (you can create more throwaway Ubuntus for this). +- An imaginary domain name to use for your headscalenet. I use `ts.plex-each` for this. + +<XesiteConv name="Mara" mood="hacker"> + `plex each` is how you spell "xe" with [Talon](https://talonvoice.com/). +</XesiteConv> + +## The Setup + +First, create a new NixOS VM on your [waifud](https://github.com/Xe/waifud) cluster: + +``` +waifuctl create -m 4096 -c 4 -H pneuma -s 25 -d nixos-unstable -z arsene/vms +``` + +<XesiteConv name="Aoi" mood="wut"> + Wait, what. Isn't waifud still in development? Doesn't it require you to have + extensive experience in how libvirtd works? How can we expect random readers + of this blog to have the slightest bit of domain experience required to follow + along with this? <br /> + <br /> Also, why am I here, wasn't I created for the [xeiaso.net blog](https://xeiaso.net/characters#aoi)? +</XesiteConv> +<XesiteConv name="Mara" mood="happy"> + Yes, waifud is still deep in development. If you don't have a local waifud + cluster around, you can use your favorite VM hosting platform such as Proxmox, + ESXi, or yolo-qemu. You can also use a cloud provider such as AWS, GCP, or + Azure. You can also use a bare metal server, but that's a bit more complicated + and I don't want to get into that here. <br /> <br /> + Also, you're not here, you're also in a VM. +</XesiteConv> +<XesiteConv name="Aoi" mood="coffee"> + What. Okay. I'm not even going to ask. +</XesiteConv> + +Be sure to set your SSH keys as root if you are using the +`nixos-unstable-within` image. This is a known issue with how that image, +cloud-init, and NixOS conflict on how user creation works. + +SSH in as root and ensure you can get in: + +``` +$ ssh root@10.77.131.232 +Warning: Permanently added '10.77.131.232' (ED25519) to the list of known hosts. +Last login: Fri Mar 31 00:02:08 2023 from 10.77.131.1 + +[root@baelzeb-weedle:~]# +``` + +Perfect! Now open a new terminal window and open `/etc/nixos/configuration.nix` in your Emacs session in [TRAMP mode](https://www.emacswiki.org/emacs/TrampMode): + +``` +$ e /ssh:root@10.77.131.232:/etc/nixos/configuration.nix +``` + +<details> +<summary>If the file doesn't exist</summary> + +If that file doesn't exist (because you are using the `nixos-unstable-within` image), create it with this template: + +```nix +{ lib, pkgs, config, ... }: + +{ + boot.initrd.availableKernelModules = + [ "ata_piix" "uhci_hcd" "virtio_pci" "sr_mod" "virtio_blk" ]; |
