diff --git a/content/posts/headscale-for-tailscale-vpn.md b/content/posts/headscale-for-tailscale-vpn.md new file mode 100644 index 0000000..491d05c --- /dev/null +++ b/content/posts/headscale-for-tailscale-vpn.md @@ -0,0 +1,153 @@ +--- +title: Heads or Tailscale VPN +date: 2023-10-31T15:01:39-07:00 +draft: false +type: post +showTableOfContents: true +tags: + - vpn + - tailscale + - headscale + - opensource + - server + - homelab + - network +--- +# Overview +This guide outlines how to set up [Headscale](https://headscale.net/) running as Docker container behind a reverse proxy (Traefik). It uses a free ubuntu VPS from the Oracle Cloud Free Tier, but any linux-based host with public IP and about ~1GB of memory should work for small Home Lab setups. + +Headscale is an opensource reverse-engineered implementation of the closed source Tailscale coordination server. There are many advantages to using the original Tailscale coordination server, such as a feature admin panel and multiple tailnets. However, I am on a quest to explore opensource and privacy-focused software, I've decided to set up Headscale as my Tailscale coordination server. + +Setting up Headscale behind a reverse-proxy is not something that the maintainers support or use themselves, but it _is_ a feature that is often [requested by community members](https://github.com/juanfont/headscale/issues/527). I wanted to see if I could identify a way to configure Headscale behind Traefik as a reverse proxy. The following is my working prototype. +#### Prerequisites +- Linux VPS with Public IP and ~1GB of memory +- Traefik running in docker container ([Review this guide](/posts/traefik-reverse-proxy)) +- Public domain +- [Must read this Headscale documentation](https://github.com/juanfont/headscale/blob/main/docs/reverse-proxy.md) +# VPS Setup +1. Create a free VPS with Oracle Cloud. +2. Point a hostname to the public IP of your VPS (e.g. `headscale.example.com`). +3. Update packages and install docker and docker-compose. +4. Set up a container running Traefik as described in [this guide](/posts/traefik-reverse-proxy). +# Headscale Setup +1. Login to the VPS with SSH. +2. Create a directory for Headscale: `mkdir /srv/apps/headscale` +3. Change to that directory: `cd /srv/apps/headscale` +4. Create a compose.yml file and paste the following into, updating values as required: + +```yaml +services: + headscale: + image: headscale/headscale:latest + container_name: headscale + hostname: headscale + labels: + - traefik.enable=true + - traefik.http.routers.headscale-example-com.tls=true + - traefik.http.routers.headscale-example-com.rule=Host(`headscale.example.com`) + - traefik.http.routers.headscale-example-com.service=headscale-example-com + - traefik.http.services.headscale-example-com.loadbalancer.server.port=8080 + ports: + - 3478:3478/udp # did not need to open in Oracle VPC firewall + volumes: + - ./data/headscale:/var/lib/headscale + - ./data/config:/etc/headscale + networks: + - proxy + restart: unless-stopped + command: "headscale serve" + +networks: + proxy: + external: true +``` + +5. Create the config directory: `mkdir -p data/config` +6. Create the sqlite db: `touch data/config/db.sqlite` +7. Create and edit the config file: `vi data/config/config.yaml` (**.yaml** not .yml seems to matter) +8. Paste in the configuration below, updating values as required: + +```yaml +--- +server_url: https://headscale.example.com +listen_addr: 0.0.0.0:8080 +metrics_listen_addr: 0.0.0.0:9090 +grpc_listen_addr: 0.0.0.0:50443 +grpc_allow_insecure: false +private_key_path: /var/lib/headscale/private.key +noise: + private_key_path: /var/lib/headscale/noise_private.key +ip_prefixes: + - fd7a:115c:a1e0::/48 + - 100.64.0.0/10 +derp: + server: + enabled: false + region_id: 999 + region_code: "headscale" + region_name: "Headscale Embedded DERP" + stun_listen_addr: "0.0.0.0:3478" + urls: + - https://controlplane.tailscale.com/derpmap/default + paths: [] + auto_update_enabled: true + update_frequency: 24h +disable_check_updates: false +ephemeral_node_inactivity_timeout: 30m +node_update_check_interval: 10s +db_type: sqlite3 +db_path: /etc/headscale/db.sqlite +acme_url: https://acme-v02.api.letsencrypt.org/directory +tls_letsencrypt_challenge_type: HTTP-01 +tls_letsencrypt_listen: ":http" +tls_cert_path: "" +tls_key_path: "" +log: + format: text + level: info +acl_policy_path: "" +dns_config: + override_local_dns: true + nameservers: + - 1.1.1.1 + - 1.0.0.1 + domains: [] + magic_dns: true + base_domain: example.com +unix_socket: /var/run/headscale/headscale.sock +unix_socket_permission: "0770" +logtail: + enabled: false +randomize_client_port: false +``` + +**Note:** [The full Headscale configuration](https://github.com/juanfont/headscale/blob/main/config-example.yaml) with comments and default values can be found on their Github. This original will likely be useful when debugging. + +# Connecting Tailscale Nodes +This process is fairly straight forward and based on the [Headscale documentation](https://headscale.net/running-headscale-linux/#using-headscale). +The only caveat is that you need to prefix the `tailscale` commands with `docker exec [tailscale_container]...` +# Toubleshooting +- Headscale makes a [larger debug-focus version of the headscale image](https://headscale.net/running-headscale-container/#debugging-headscale-running-in-docker). This is useful to include more tools within the container to check connections and troubleshoot. + +It took me a little bit of testing to arrive at the combination of URL and listening address. In the end, I found that the following worked well. Initially I was trying to use port 443 (which some other tutorials showed) and received errors like `Client sent an HTTP request to an HTTPS server.` +```yaml +server_url: https://headscale.example.com +listen_addr: 0.0.0.0:8080 +``` + +It was important to leave the `tls_cert_path` and `tls_key_path` empty, as discussed on the [Headscale Github](https://github.com/juanfont/headscale/blob/main/docs/tls.md#bring-your-own-certificate). +```yaml +acme_url: https://acme-v02.api.letsencrypt.org/directory +tls_letsencrypt_challenge_type: HTTP-01 +tls_letsencrypt_listen: ":http" +tls_cert_path: "" +tls_key_path: "" +``` + +If you have suggestions or would like another pair of eyes to toubleshoot, please reach out by opening an issue in the repo that tracks this website. You can find it here: + +[https://github.com/radarsymphony/radarsymphony.github.io/issues](https://github.com/radarsymphony/radarsymphony.github.io/issues) +# Resources +- [Headscale discussion on reverse-proxies](https://github.com/juanfont/headscale/blob/main/docs/reverse-proxy.md) +- [Headscale documentation on running as container](https://headscale.net/running-headscale-container/) +- [Another blog outlining a similar process](https://techoverflow.net/2022/12/28/headscale-docker-compose-config-for-traefik-https-reverse-proxy/) diff --git a/content/posts/local-dns-with-bind9.md b/content/posts/local-dns-with-bind9.md index 17bb2e7..e5486d0 100644 --- a/content/posts/local-dns-with-bind9.md +++ b/content/posts/local-dns-with-bind9.md @@ -10,6 +10,7 @@ tags: - bind9 - resolver - docker + - network --- # Overview This short article outlines the steps to set up a local DNS server using [BIND9](https://bind9.net/) and Docker on a Raspberry Pi. This approach enables you to manage your own zone(s) for local services running in a Home Lab. It may also help cache DNS queries to reduce lookup time for frequently requested resources. I've only tested this approach in protected local networks. diff --git a/content/posts/tailscale-mesh-vpn.md b/content/posts/tailscale-mesh-vpn.md new file mode 100644 index 0000000..869fdc1 --- /dev/null +++ b/content/posts/tailscale-mesh-vpn.md @@ -0,0 +1,83 @@ +--- +title: Tailscale Mesh VPN +date: 2023-10-31T13:47:56-07:00 +draft: false +type: post +showTableOfContents: true +tags: + - VPN + - homelab + - tailscale + - network + - docker +--- +# Overview +[Tailscale](https://tailscale.com/) is an easy to configure mesh VPN. It uses [NAT traversal](https://tailscale.com/blog/how-nat-traversal-works/) to connect peers to each other. This article will outline the steps to set up Tailscale running in Docker as if it were running on the docker host directly (without SSH over the VPN - yet). This approach enables managing the Tailscale connection as you would any other docker service and creates a portable and deploy-able compose.yml to run on other systems. +# Tailscale Account +Tailscale makes use of a control panel to orchestrate and connect nodes. In order to connect your devices together, you need to create an account with Tailscale. + +> In [this article](/posts/headscale-for-tailscale-vpn), I modify the VPN outlined here to move away from the closed source Tailscale control server to the opensource Headscale control server. + +1. Create an account with Tailscale [login.tailscale.com](https://login.tailscale.com/) +2. Go to **Settings** > **Personal Settings** > **Keys** +3. Click **Generate auth key**, turn on **Reusable** +4. Click **Generate key** and save the value. +# Docker Compose +1. Create a directory to host this service: `mkdir /srv/apps/tailscale` +2. Change into that directory: `cd /srv/apps/tailscale` +3. Create a compose.yml file: `touch compose.yml` +4. Open the file up with an editor and paste in the following: + +```yaml +services: + tailscale: + image: tailscale/tailscale + container_name: tailscale + network_mode: "host" + environment: + - TZ=[YOUR_TIMEZONE] + - TS_HOSTNAME=${HOSTNAME}-tailscale + - TS_AUTHKEY=[TS_AUTHKEY] + - TS_STATE_DIR=/tailscale/state + - TS_SOCKET=/var/run/tailscale/tailscaled.sock + - TS_TAILSCALED_EXTRA_ARGS=--tun=tailscale0 # important + - TS_DEBUG_FIREWALL_MODE=nftables + - TS_NO_LOGS_NO_SUPPORT=true + volumes: + - ./data/tailscale/state:/tailscale/state + - /dev/net/tun:/dev/net/tun # important + cap_add: + - net_admin + - sys_module + restart: unless-stopped +``` + +5. Update the TS_AUTHKEY that you generated in the account. +# Start Tailscale +1. While logged in to the Tailscale control panel, go to [the machines tab](https://login.tailscale.com/admin/machines). +2. In your terminal at the Tailscale directory, run: `docker-compose up -d` +3. Refresh the machines tab and you should see a new node appear. +# Testing +A quick way to test if the VPN is working is to install the [Tailscale app on a mobile device](https://tailscale.com/downloads). You should be able to see both devices registered in your machine's tab in Tailscale. +# Troubleshooting +Start simple and progress in small steps. When I set this up, I started with installing the Tailscale binary on two servers (no Docker) exactly like the Tailscale documentation described. This approach allowed me to just see if the two hosts would be able to connect as intended before adding another layer of complexity. I then slowly transitioned one server to use Docker, then the other. + +Oracle Cloud Free Tier allows the provision of a small VPS within minutes that can be useful for having another remote (plain/fresh) node to set up Tailscale on and test iterations. + +I frequently ran `docker exec tailscale tailscale [status|ping ]` to see if the current node was registering other nodes and to gain insight into things like whether it was using IPv4 or IPv6. + +I initially had issues with [iptables vs nftables](https://github.com/tailscale/tailscale/issues/5621) and found that for my devices I had to set `TS_DEBUG_FIREWALL_MODE=nftables`. If you encounter issues, you can try removing this value. + +To run Tailscale in Docker as if it were running on the host posed some challenges. The nodes were registering but not fully connecting to each other until I added `TS_TAILSCALED_EXTRA_ARGS=--tun=tailscale0`. By default, the [Tailscale Docker image enables "userspace-networking"](https://tailscale.com/kb/1282/docker/?q=docker#ts_userspace) which doesn't seem to work in this setup. + +Depending on your firewall, you may find pointers in the [Tailscale firewall documentation](https://tailscale.com/kb/1181/firewalls/). + +If you have suggestions or would like another pair of eyes to toubleshoot, please reach out by opening an issue in the repo that tracks this website. You can find it here: + +[https://github.com/radarsymphony/radarsymphony.github.io/issues](https://github.com/radarsymphony/radarsymphony.github.io/issues) +# Resources +- [Tailscale Terminology and Concepts reference](https://tailscale.com/kb/1155/terminology-and-concepts/) +- https://www.wundertech.net/how-to-set-up-tailscale-on-docker/ +- https://docs.ibracorp.io/tailscale/tailscale/docker-compose +- [Similar approach but Tailscale within each docker container](https://tailscale.dev/blog/docker-mod-tailscale) +- [Setting up Headscale to run in Docker behind Reverse Proxy](/posts/headscale-for-tailscale-vpn) \ No newline at end of file diff --git a/content/posts/traefik-reverse-proxy.md b/content/posts/traefik-reverse-proxy.md index 911a817..6aebc8c 100644 --- a/content/posts/traefik-reverse-proxy.md +++ b/content/posts/traefik-reverse-proxy.md @@ -10,6 +10,7 @@ tags: - reverse-proxy - homelab - https + - docker --- # Overview The following guide outlines the steps to run [Traefik](https://traefik.io/traefik/) with docker as a reverse proxy for your host. This setup enables you to resolve hostnames to particular containers running on the host. With a public domain, you can use [Traefik to request SSL certificates to enable https](https://doc.traefik.io/traefik/https/acme/) for each site.