[{"content":"What I recently used Claude Co-Work with Kali Linux to hack the Eternal Blue room in TryHackMe. My goal was to have as little involvement as possible and let AI drive most of the process. This meant having Claude also generate the docker compose file I used to spin up the Kali Linux docker container.\nWhen it was done hacking the room I had Claude Cowork generate a guide in my Obsidian vault detailing a step by step process someone could use to hack the room in the future.\nThere write-up that Claude did can be found here https://chris-smith.net/guides/eternalblue/\nDisclaimer I\u0026rsquo;ve already hacked this room before when I first started using the TryHackMe platform. So I\u0026rsquo;m not earning myself any points that I haven\u0026rsquo;t already earned by having AI hack this room.\nSetup Intial setup was very minimal and took only 10 minutes to get everything going. That includes prompting Claude for the files needed to spin up my Kali Linux container and running them.\nDownloaded the Claude cowork app from Anthropics website Setup Kali Linux using a docker compose file Claude generated Downloading the OVPN file from TryHackMe so Kali Linux could connect to the room over VPN My docker files Compose file\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 services: kali-mcp-server: build: context: . dockerfile: Dockerfile container_name: kali-mcp-server hostname: kali stdin_open: true # Required for MCP stdio transport tty: false # Keep false for MCP stdio (Claude uses exec -i) # NET_ADMIN + /dev/net/tun are required for OpenVPN cap_add: - NET_ADMIN - NET_RAW # Required by many Kali tools (nmap SYN scans, tcpdump) devices: - /dev/net/tun:/dev/net/tun # Shared folder: map ./shared on your host to /shared inside Kali # Drop files here to pass them in/out of the container volumes: - ./shared:/shared # Keep the container alive; the MCP server is invoked on-demand via # `docker exec -i kali-mcp-server python3 /app/kali_server.py` command: sleep infinity restart: unless-stopped # Uncomment the network_mode below ONLY if you need the container to # share the host network (e.g. for VPN routing to affect the host). # Leave commented for normal isolated container networking. # network_mode: host Dockerfile\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 FROM kalilinux/kali-rolling:latest # ── Kali repositories ──────────────────────────────────────────────────────── RUN echo \u0026#34;deb http://http.kali.org/kali kali-rolling main contrib non-free non-free-firmware\u0026#34; \\ \u0026gt; /etc/apt/sources.list \u0026amp;\u0026amp; \\ echo \u0026#34;deb-src http://http.kali.org/kali kali-rolling main contrib non-free non-free-firmware\u0026#34; \\ \u0026gt;\u0026gt; /etc/apt/sources.list # ── System packages ─────────────────────────────────────────────────────────── # openvpn – TryHackMe VPN connectivity # python3 + venv – MCP server runtime # Common pentest tools included for a useful base image RUN apt-get update \u0026amp;\u0026amp; apt-get install -y --no-install-recommends \\ # VPN openvpn \\ # Core utilities python3 \\ python3-pip \\ python3-venv \\ git \\ curl \\ wget \\ vim \\ net-tools \\ iputils-ping \\ iproute2 \\ dnsutils \\ procps \\ # Pentest tools nmap \\ nikto \\ sqlmap \\ gobuster \\ dirb \\ hydra \\ john \\ hashcat \\ metasploit-framework \\ netcat-traditional \\ tcpdump \\ wireshark-common \\ \u0026amp;\u0026amp; apt-get clean \\ \u0026amp;\u0026amp; rm -rf /var/lib/apt/lists/* # ── MCP server (weirdmachine64/kali-docker-mcp) ─────────────────────────────── WORKDIR /app RUN git clone https://github.com/weirdmachine64/kali-docker-mcp.git /app/kali-docker-mcp # Install Python dependencies from the cloned repo RUN python3 -m venv /app/venv \u0026amp;\u0026amp; \\ /app/venv/bin/pip install --upgrade pip \u0026amp;\u0026amp; \\ if [ -f /app/kali-docker-mcp/requirements.txt ]; then \\ /app/venv/bin/pip install -r /app/kali-docker-mcp/requirements.txt; \\ else \\ /app/venv/bin/pip install mcp asyncio; \\ fi # Copy all source files into /app/ so utils and other modules are importable # Tries src/ layout first, falls back to repo root RUN if [ -d /app/kali-docker-mcp/src ] \u0026amp;\u0026amp; [ -f /app/kali-docker-mcp/src/kali_server.py ]; then \\ cp -r /app/kali-docker-mcp/src/. /app/; \\ else \\ cp -r /app/kali-docker-mcp/. /app/; \\ fi # Make the server executable with the venv Python, running from /app so # relative imports (utils, etc.) resolve correctly RUN printf \u0026#39;#!/bin/bash\\ncd /app \u0026amp;\u0026amp; exec /app/venv/bin/python3 /app/kali_server.py \u0026#34;$@\u0026#34;\\n\u0026#39; \\ \u0026gt; /usr/local/bin/kali-mcp \u0026amp;\u0026amp; \\ chmod +x /usr/local/bin/kali-mcp # ── Shared folder mount point ───────────────────────────────────────────────── RUN mkdir -p /shared VOLUME [\u0026#34;/shared\u0026#34;] # ── OpenVPN config directory ────────────────────────────────────────────────── # Drop your TryHackMe .ovpn file into ./shared/ and connect with: # docker exec -it kali-mcp-server openvpn /shared/your-thm.ovpn RUN mkdir -p /etc/openvpn WORKDIR /app Adding MCP Server to Claude Once your docker containers have been spun up I needed to add Kali\u0026rsquo;s MCP server to Claude so it knows how to access it. The MCPs servers are added in Claude\u0026rsquo;s claude_desktop_config.json file.\nDefault config file locations Windows: ~/Library/Application Support/Claude/claude_desktop_config.json MacOS: ~/Library/Application Support/Claude/claude_desktop_config.json Linux: ~/.config/Claude/claude_desktop_config.json\nCode to add the MCP server\n1 2 3 4 5 6 7 8 9 10 11 12 13 \u0026#34;mcpServers\u0026#34;: { \u0026#34;kali-mcp-server\u0026#34;: { \u0026#34;command\u0026#34;: \u0026#34;/usr/local/bin/docker\u0026#34;, \u0026#34;args\u0026#34;: [ \u0026#34;exec\u0026#34;, \u0026#34;-i\u0026#34;, \u0026#34;kali-mcp-server\u0026#34;, \u0026#34;/app/venv/bin/python3\u0026#34;, \u0026#34;/app/kali_server.py\u0026#34; ], \u0026#34;env\u0026#34;: {} } }, After the above code has been added to the config file you\u0026rsquo;ll need to restart the Claude desktop app. On the next startup you should see a message that Claude has either successfully or unsuccessfully connect to the MCP server. If it was unsuccessful you can click the message and there should be an option to view the logs. You can paste the logs back into Claude for help diagnosing the connection issue. Also make sure your Kali docker container is running!\nLets start hacking Asking Claude to connect to TryHackMe For my first command I asked Claude to connect to the TryHackMe VPN and it immediately confirmed the VPN connection was active and returned back it\u0026rsquo;s connection information.\nI then spun up the Eternal Blue room vulnerable box and asked Claude if it could see that IP address which it also confirmed that it could.\nNow that everything is online and Claude can see it, the only next thing to do would be running a port scan. Claude confirmed it started the scan and then returned back a beautiful chart of all the open running ports with their descriptions. It also returned back results showing that ports 445 and 3389 were of particular interested.\n\u003e NMAP Scan Results/figcaption\u003e Claude identified the port and asked if we should investigate further to which I said do it. It then returned back that indeed port 445 was vulnerable to the MS17-010 (EternalBlue) vulnerability. It also returned back a lot of helpful information such as OS information and a brief synopsis of the vulnerability itself.\nVulnerability Scan Results So to recap what Claude has been able to do so far and what it easily accomplishes: - See the vulnerable machine - Run a port scan and return detailed results and analysis - Run a vulnerability Scan and determine 445 is vulnerable to EternalBlue - Exploit port 445 opening a meterpreter session to the vulnerable PC - Dumping user hashes and cracking the Jon user password.\nEverything in the list above was easy and instantly done using Claude Cowork. But this is the point where Claude starts to stumble and I need to intervene. Ironically at this point Claude already has system level access to the vulnerable PC and only needs to read the contents of the files containing the flags. But even when I specifically give Claude the file locations for the flags it still has issues trying to view the contents.\nOnce Claude has issues reading the files it starts getting creative. It starts to try and download the files to temp locations to read them there or it starts to generate it\u0026rsquo;s own scripts that it can use to do a different kind of exploit that might help. The vulnerable room starts crashing frequently and I find out later Claude had around 20 active remote connections all trying different things.\nNot only was I overwhelming the remote Vulnerable VM, I was also chewing through my daily Claude usage. Right when Claude tells me it had a breakthrough, it also tells me that sorry my limit is reached and I have to wait for a daily reset at 9pm.\nClaude limit reached Hacking results I did come back at 9pm to try again when my Claude usage limits reset. I even tried guiding Claude to the answers it needed. But I was only ever able to extract the first flag. This is definitely an issue a human user would have been able to diagnose and figure out quicker and where AI had a big fumble. But getting to this point so easily was super impressive and scary.\nI heard that the latest version of Kali that released also includes a Kali-MCP server by default. This project helped give me a huge understanding of how MCP servers work and their benefit. I can see how if I\u0026rsquo;m hacking a room in the future I could use the MCP server and an AI of my choice to help me when I\u0026rsquo;m stuck. It would also be able to better explain what\u0026rsquo;s happening and why while I\u0026rsquo;m doing it which is a huge learning opportunity.\nObsidian Because Obsidian is just a large grouping of markdown files, Claude desktop has an easy time viewing and writing to it. I only had to tell Claude to write a guide to my Obsidian and specify the location of my vault. The guide came out amazing and you can view it here\n","date":"2026-03-22T00:00:00Z","image":"https://cdn.chris-smith.net/homelab/eternalBlueClaude/Gemini_Generated_Image_lhc0qalhc0qalhc0-d629a259.png","permalink":"https://chris-smith.net/posts/aihacking/","title":"Hacking with Claude"},{"content":"What I tried creating my very first vibe coded project using ChatGPT\u0026rsquo;s Codex app.\nLink to my vibe coding project: https://github.com/tohaku/BlogPhotoUpload\nAbout Recently on the Diary of a CEO podcast, the host stated he\u0026rsquo;d rather hire someone who can vibe code or use AI to generate what they need instead of hire an engineer. More and more I keep hearing that AI is going to kill SAAS because teams are vibe coding the apps they need instead of paying for an app that might not satisfy exactly what they need. When I hear these things it makes me wonder what tools I could make that would make my work easier or make my home projects easier.\nOne thing that costs me a bit of time is adding images to my blog posts. My old workflow was very manual and involved connecting to Cloudflare R2 with Cyberduck to upload my screenshots. Then since I could never remember the exact code for embedding images in blog posts, I\u0026rsquo;d usually have to go back to my old posts, copy image code, and manually update the URL to use it in my new post. Even then I might have to troubleshoot why an image isn\u0026rsquo;t showing because I typed something incorrectly.\nChatGPT Codex The app I vibe coded saves me a bit of time by automatically uploading images I select to my Cloudflare R2 bucket and provides the image code I need to show the image in my blog post. It also stores all of the API keys hashed in an SQLite databse so I can keep those keys secure.\nFirst attempt, web app The first attempt was amazing. In just one prompt I had generated a web app that did everything I wanted and looked nice.\nRe-created as a local python app My first attempt was amazing but I changed my mind from having a web app to an app I could run locally. So I told ChatGPT to change it, and it re-did the app in Python. It also assumed the project would be automatically uploaded to Github without me specifying that and generated the instructions needed for users to try the same project, as well as a gitignore file to prevent secure information from getting uploaded to Gitub and leaked.\nLogs added to the app For my final change I added the ability to output logs and prevent leaking any information in those logs. Initially it was leaking identifiable information.\nFinal thoughts I was blown away by how easy it was to create this app. A day of random brain storming and a 10 minute prompt gave me the exact program I wanted to make blogging easier.\nPotential future additions. These could easily just be one or two more prompts to add to my existing app.\nFix the UI to be more responsive Fix image URLs to automatically include https:// Add the option to specify and include an image caption ","date":"2026-03-22T00:00:00Z","image":"https://cdn.chris-smith.net/homelab/1stvibe/Screenshot-2026-03-30-at-8.04.05%E2%80%AFPM-2c9d799e.png","permalink":"https://chris-smith.net/posts/firstvibe/","title":"Tried Vibe Coding"},{"content":"What/Why? Setting up OIDC (PocketID) so that anyone accessing my links in Cloudflare must first be authenticated. This helps add an additional layer of protection by limiting exposure of your apps to the greater web.\nBefore you start I\u0026rsquo;m assuming both PocketID and Cloudflare tunnels are already set up.\nMy PocketID guide can be found here.\nSetup Identity Provider Setup or grab your team name in Cloudflare You\u0026rsquo;ll need your team name for the callback URL in PocketID.\nLogin to Cloudflare One Settings Team name and domain -\u0026gt; Team name Add Cloudflare as an OIDC Client Login to PocketID Administration -\u0026gt; OIDC Clients Click Add OIDC Client button Enter any name you want Enter callback URL (example below) 1 https://\u0026lt;your-team-name\u0026gt;.cloudflareaccess.com/cdn-cgi/access/callback Check the option for PKCE\nClick save\nSave the Client ID and Client Secret provided.\nGrab two more pieces of information for Cloudflare. All the URLs you need can be found at your PocketID\u0026rsquo;s OpenID configuration endpoint:\nToken URL Authorization URL Certificate URL (often called jwks_uri) You can find these values by visiting https://\u0026lt;Your-PocketID-URL\u0026gt;/.well-known/openid-configuration Add PocketID as a login method to Cloudflare Zero Trust From your Cloudflare homepage, click Zero Trust Integrations -\u0026gt; Identity Providers Add OpenID Connect Fill out the following fields using the saved information from PocketID Name: any name you want App ID: The Client ID you saved from PocketID Client Secret: The Client Secret you saved from PocketID Auth URL: https://subdomain.domain.com/authorize Token URL: https://subdomain.domain.com/api/oidc/token Certificate URL: https://subdomain.domain.com/.well-known/jwks.json Check the box for PKCE Save Click the Test button to make sure your configuration is correct. Secure your apps I\u0026rsquo;m going to set up a rule to protect all of my applications with PocketID, except for a few I\u0026rsquo;ll specify later. To do this, I\u0026rsquo;ll use a wildcard in the initial application rule instead of configuring each app individually.\nSet up apps that go through PocketID From the Cloudflare homepage, click Zero Trust Access controls -\u0026gt; Applications Click the add an application button Self hosted Basic information You can add applications individually, but I\u0026rsquo;ll use a wildcard (*) to protect most of them at once. Name: Allow All Add public hostname Subdomain: * Domain: my domain Access policies Create new policy (this opens a new page) Policy name: Allow ALL Include: Set the selector to Everyone Click Save. You\u0026rsquo;ll be returned to the application setup page. Back under access policies Select an existing policy Select your new Allow ALL policy Login methods Check only PocketID Check Apply instant authentication. This forwards users directly to PocketID for a more seamless login experience, bypassing the Cloudflare Access screen. Disable WARP authentication identity Click next I didn\u0026rsquo;t change anything here, click next again I left the defaults here as well, click save Set up apps not to be protected by PocketID Because I used a wildcard to protect all applications, I\u0026rsquo;m also blocking PocketID behind itself, which will fail. Here, we\u0026rsquo;ll create a rule to bypass authentication for PocketID and any other apps you don\u0026rsquo;t want protected.\nFrom the Cloudflare homepage, click Zero Trust Access controls -\u0026gt; Applications Click the add an application button Self hosted Basic information Name: Bypass PocketID Add a public hostname Subdomain: pocketid (or your actual PocketID subdomain) Domain: my domain repeat adding a public hostname for each app you don\u0026rsquo;t want blocked Add policy\nAccess policies (going to create a new bypass policy) Create new policy (this opens a new page) Policy name: Bypass Action: Bypass Include: Set the selector to Everyone Click Save. You\u0026rsquo;ll be returned to the application setup page. Back under access policies Select an existing policy Select your new Bypass policy Click next I didn\u0026rsquo;t change anything here, click next again I left the defaults here as well, click save Next steps Congratulations! At this point, every URL except those you\u0026rsquo;ve set to bypass should be protected by PocketID authentication.\nThe next step is to configure your applications to trust Cloudflare for Single Sign-On (SSO). This will allow users to be automatically signed in after authenticating with PocketID, avoiding a second login prompt for each app.\n","date":"2026-03-15T00:00:00Z","image":"https://cdn.chris-smith.net/homelab/cloudflareoidc/banner.png","permalink":"https://chris-smith.net/posts/cloudflareoidc/","title":"OIDC with Cloudflare"},{"content":"What it is Cockpit is a program you can install on your Linux hosts that allows you to monitor and manage them from your web browser.\nKey Features Manage multiple Linux hosts from one web UI Terminal, services, and logs in one place Built-in dashboards for resource usage Runs updates and basic admin tasks without SSHing everywhere Uses your existing system users and permissions Installation Setup is super simple. The main documentation can be found here.\nInstall on Ubuntu It\u0026rsquo;s one simple command to get it installed without any need for configuration afterwards.\n1 2 sudo apt update sudo apt install cockpit Accessing web UI After the install you can access your cockpit instance by going to https://server-IP:9090\nMultiple Hosts Adding additional hosts is also really simple. You\u0026rsquo;ll want to designate one host as the default to add all of your hosts too. My main host is called The Curator and is used for my Wazuh SIEM server. So it\u0026rsquo;s fitting it\u0026rsquo;ll be the default host for all of my Cockpit setups.\nSteps\nInstall Cockpit on the additional hosts Click the dropdown in the top left Select Add new host Enter the details for the new host It\u0026rsquo;ll work with IP address, alias name or an ssh://URI Once you\u0026rsquo;ve authenticated you\u0026rsquo;ll see the host listed in your sidebar so you can switch between the two. You’re all set to manage your Linux hosts from your web browser!\nTroubleshooting If you\u0026rsquo;re unable to access the web UI you may need to:\nActivate the software 1 sudo systemctl enable --now cockpit.socket If you have the firewall enabled you may need to unblock it. For UFW that would be 1 sudo ufw allow 9090/tcp ","date":"2026-01-02T00:00:00Z","image":"https://cdn.chris-smith.net/homelab/cockpit/banner.png","permalink":"https://chris-smith.net/posts/cockpit/","title":"Cockpit"},{"content":" Alert!! At the time of writing this post Playit.GG has disabled UDP ports for free accounts. Premium accounts are $3 a month or $30 a year.\nWhat is PlayIt.GG PlayIt.GG is a tunneling service that exposes your self hosted game servers to the internet. This lets you share your servers with friends or the public without them needing software to connect into your home network. The only other way to expose your game servers to the internet is by setting up port forwarding on your router assentially poking holes into what seperates your home network from the outside world.\nPlayIt.GG alternatives With the recent changes to playIt.GG you might be more interested in these alternatives.\nOracle Cloud Free Tier with Pangolin Oracle offers a service, Oracle Cloud Free Tier, that\u0026rsquo;s free to host on up to a certain point. You can pair that with another service called Pangolin that you can use to essentially make your own Playit.GG service. As long as you only share it with a few friends, you shouldn\u0026rsquo;t breach the bandwidth limits. You can even give your friends login access (it even integrates with PocketID) to Pangolin to create their own tunnels.\nTailscale Another alternative that\u0026rsquo;s my favorite would be Tailscale. Tailscale essentially creates a virtual network between everyone who\u0026rsquo;s using the Tailscale software and was invited into your network. As long as your game servers are exposed to the Tailscale network, anyone on yours can access them.\nI already use Tailscale as a way to access my internal services that aren\u0026rsquo;t exposed to the internet and have ACLs setup to control what users on the Tailscale network can see.\nThe downside of Tailscale is that your friends would have to download the Tailscale software to connect to your network which most people are reluctant to do.\nHow PlayIt.GG works To setup playit.GG you\u0026rsquo;ll need to download an agent onto your host PC that connects to your account. Then from your account you\u0026rsquo;ll create tunnels that\u0026rsquo;ll route external IPs:Ports to your internal game servers.\nFirst steps - Setup account The first thing you\u0026rsquo;ll want to do is setup your account on playit.gg. You\u0026rsquo;ll need this account to register the agent after it\u0026rsquo;s installed.\nSetting up the agent Ubuntu Linux Installing the agent\n1 2 3 4 curl -SsL https://playit-cloud.github.io/ppa/key.gpg | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/playit.gpg \u0026gt;/dev/null echo \u0026#34;deb [signed-by=/etc/apt/trusted.gpg.d/playit.gpg] https://playit-cloud.github.io/ppa/data ./\u0026#34; | sudo tee /etc/apt/sources.list.d/playit-cloud.list sudo apt update sudo apt install playit If you want PlayIt.GG start when the computers starts you\u0026rsquo;ll need to run these commands.\n1 2 sudo systemctl start playit sudo systemctl enable playit Register your playIt.GG instance with your account. After running the below command you\u0026rsquo;ll be provided with a link in your terminal. Clicking the link opens a web browser so you can authenticate with your account.\n1 playit setup Setting up your first tunnel Now that you\u0026rsquo;ve setup your agent you can start setting up tunnels to expose your game servers to the internet. Unless you\u0026rsquo;re able to use the pre-defined tunnels this step can be a bit confusing and took me time to wrap my head around.\nPre-defined Tunnels (Minecraft, Hytale, etc) If you\u0026rsquo;re setting up a tunnel for one of the games listed below, and are using the default ports, this will be easy to setup.\nSteps:\nClick on tunnels in the navigation bar at the top of the page Your agent should show as connected Click add tunnel If you\u0026rsquo;re using the free version version leave it on Global Anycast If you\u0026rsquo;re paying change this to a data center closer to your server For tunnel type select one of the pre-defined games. Leave enabled tunnel selected and click add tunnel Pre-defined tunnels\nMinecraft (Bedrock or Java) Hytale Valheim Terraria Project Zomboid Starbound Custom tunnels If your game wasn\u0026rsquo;t listed the tunnel setup can be a bit trickier but possible. The reason it can be confusing is that most servers have two ports: a query port for Steam and a game server port that your game connects to. When setting up your tunnel you can specify however many ports you need but you\u0026rsquo;re only allowed to specify one port number. That statement is probably confusing but I\u0026rsquo;ll break it down.\nBecause you\u0026rsquo;re only able to specify one port number there are two ways to go about the tunnel setup: change your game so that the query port and server port are consecutive numbers or we\u0026rsquo;ll create a tunnel for each port.\nUsing one tunnel The first method for setting up your tunnel is to change your game server so that the query port and server port are consecutive.\nYou\u0026rsquo;ll want to make it so that your query port comes first, similar to below.\nQuery port = 2224 Game Server port = 2225 So lets go through the tunnel creation steps:\nOn the PlayIt.GG site, click tunnels in the top navigation bar Your agent should show as online and in green Click add tunnel Region: select the one closest to your server Tunnel Type: you\u0026rsquo;ll more than like need TCP+UDP Accept the prompt that you agree not to host malware You might be prompted to reselect your region and Tunnel type Tunnel description: I like to put what game I\u0026rsquo;m hosting here Port count: More than likely 2, unless you need a different amount. Local port: The port number of your query, ie 2224 Click add tunnel Congrats your tunnel should be created and listed! Click the tunnel to view it\u0026rsquo;s properties Specify your servers local address and click update Port number can stay the same unless you change it. Congrats on setting up your tunnels! You\u0026rsquo;re not ready to connect to it. Using multiple tunnels The second option for creating custom tunnels is by creating a seperate tunnel for each port. This method works better if you can\u0026rsquo;t change the port numbers your server runs on or you don\u0026rsquo;t want to. For this method you\u0026rsquo;ll probably only need a tunnel for the game server port and a second tunnel for the query port.\nExample ports for server. Note they\u0026rsquo;re not sequential.\nQuery port = 2224 Game Server port = 8888 Setup Steps:\nOn the PlayIt.GG site, click tunnels in the top navigation bar Your agent should show as online and in green Click add tunnel Region: select the one closest to your server Tunnel Type: you\u0026rsquo;ll more than like need TCP+UDP Accept the prompt that you agree not to host malware You might be prompted to reselect your region and Tunnel type Tunnel description: I like to put what game I\u0026rsquo;m hosting here For number of ports leave at 1 Click add tunnel Click into the tunnel to modify it\u0026rsquo;s properties. specify the IP of your server give the tunnel a name. I like to name it after the port functionality like Hytale Query Port Save your change to the tunnel. Repeat the above steps for your second tunnel and however many more you need. If the last one was the query port, this is the game port. Congrats on setting up your tunnels! You\u0026rsquo;re not ready to connect to it. Connecting to your game After creating your tunnels PlayIt.GG will provide a public {domain name}:port address and a public IP:port address that you can use to connect to your server.\nIf you\u0026rsquo;re using the multiple tunnel setups you\u0026rsquo;ll want to use the public address for your query port tunnel. That\u0026rsquo;s all Steam needs to connect.\nSteps to add the game server to steam:\nIf the game is already runny press Shift+F2 to view Steam\u0026rsquo;s UI The click the icon at the bottom for game servers If you\u0026rsquo;re not in game and just have Steam open you can find this option in the view menu -\u0026gt; game servers In the game servers window go to the favorites tab. Click the + icon to add a new server Paste the address from PlayIt.GG and click ok. The server should show up as online and available in your favorites list now. Your friends will probably need to do the same to also connect to the server.\nSetting up a custom domain If you\u0026rsquo;ve subscribed to PlayIt.GG it lets you use your own domain name instead of the random one they provide. The IP address will still be random but they also offer a static IP at an additional price. For me I\u0026rsquo;ve had plenty of luck with using the domain name and haven\u0026rsquo;t needed to pay for the static IP.\nSetup Steps:\nIn PlayIt.GG go to Settings -\u0026gt; Domains You\u0026rsquo;ll be provided two DNS records that you\u0026rsquo;ll need to put into your name server, in my case that\u0026rsquo;s Cloudflare. Applying the DNS records login into Cloudflare Click your domain name -\u0026gt; DNS -\u0026gt; Records Create two new DNS records, one for each nameserver provided by playit.GG. Subdomain is the same for both. Type: NS Name: chosen subdomain Nameserver: Name server provided by playit.GG TTL: left on Auto Back in Playit.GG click the orange button that says add external domain, type your base domain, ie fiddlesticks.com and apply it. It can take some time for your DNS records to update and for your domain to be added. Once it is, you\u0026rsquo;ll see it listed under settings -\u0026gt; domains and can apply it to your tunnel. (Optional) You can also click into the domain name and add multiple subdomains which is useful if you have multiple game servers (ie enshrouded.fiddlesticks.com and palworld.fiddlesticks.com). You\u0026rsquo;ll just need to make sure to create more NS records in Cloudflare for each of the subdomains. Now when you view your tunnel settings you\u0026rsquo;ll see your domain name with a port number (ie mydomain.fiddlesticks.com:24220) that you and your friends can use to connect to the server.\n","date":"2026-01-02T00:00:00Z","image":"https://cdn.chris-smith.net/homelab/playitgg/banner.png","permalink":"https://chris-smith.net/posts/playitgg/","title":"PlayIt.GG"},{"content":" ┌───────────────────────────┐ │ Tailscale Network │ │ (your laptop / phone) │ └──────────────┬────────────┘ │ Encrypted Tailscale │ DNS resolves subdomain │ fruity.pebbels → 100.x.x.x (NGINX Tailscale IP) sonic.pebbels → 100.x.x.x nugget.pebbels → 100.x.x.x │ ▼ ┌──────────────────────────┐ │ NGINX Reverse Proxy │ │ (Tailscale-enabled) │ │ IP: 100.x.x.x │ └──────────────┬───────────┘ │ ┌────────────────────────────┼─────────────────────────────┐ ▼ ▼ ▼ Service 1 Service 2 Service 3 What is Tailscale Tailscale is a software that basically creates a virtual LAN between devices no matter where they are in the world. You could use it to have your own Halo LAN party with friends all over the world or use it to share your self hosted services with friends and family without exposing them to the public internet.\nTailscale setup This post assumes you\u0026rsquo;ve already setup Tailscale on your devices. If you have a setup similar to mine Unraid has a plugin and guide that makes setup really easy.\nUnraid Setup guide: https://docs.unraid.net/unraid-os/system-administration/secure-your-server/tailscale/?utm_source=google\u0026amp;utm_medium=cpc\u0026amp;utm_campaign=p-max-targeted-us-can\u0026amp;utm_content=\u0026amp;utm_term=\u0026amp;gad_source=1\u0026amp;gad_campaignid=21440886943\u0026amp;gbraid=0AAAAAC26wCIJdzZTNqIwpiXcILb9L2B8F\u0026amp;gclid=Cj0KCQiA_8TJBhDNARIsAPX5qxQ_G4SDhF1F3kffSiwJrQk8zHZJlXqZWEr3oEEzbu7wHXcf6ZAhDw0aAh2MEALw_wcB\nSo what is this post about? There are some services I don\u0026rsquo;t want to expose directly to the internet but I\u0026rsquo;d like to still be able to access them while travelling. Unraid makes it possible to expose each of your services directly to Tailscale but that\u0026rsquo;s too insecure.\nMy home network is already segmented with multiple VLANs with an NGINX container being the only service permitted on the firewall that I can use to access everything. I can do the same thing with Tailscale where only NGINX is exposed and will route all of my traffic.\nSetup First step - Enable Tailscale on the NGINX container For my NGINX container I use the one from LinuxServer.io (lscr.io/linuxserver/nginx). The template contains an option to enable Tailscale. It doesn\u0026rsquo;t need anything special other than specifying the name that\u0026rsquo;ll appear in the Tailscale admin panel.\nSecond step - Configure Tailscale In this portion we\u0026rsquo;re going to modify some settings in the Tailscale admin panel.\nEnable Magic DNS Go to the DNS tab https://login.tailscale.com/admin/dns Scroll towards the bottom and click the button to enable Magic DNS Specify your name server On the same DNS page as step 2, specify your DNS server under the Nameservers section. You can use something like PiHole here, I use my router that supports custom DNS. You\u0026rsquo;ll also need to provide a domain name while specifying the IP. If you\u0026rsquo;re using a URL like fruity.pebbels , pebbels would be the name to specify. Then all of your URLS will need to end in .pebbels. Third step - Configure DNS For my setup I use my Unifi Dream Machine Pro router as my DNS server and it supports custom DNS. If your router doesn\u0026rsquo;t support custom DNS you can use something like PiHole.\nFor the Unifi Dream Machine, you can do this by creating new policies and select DNS as the type. Then create one for each of the services you want to access and specify the IP of your NGINX container that\u0026rsquo;s on Tailscale.\nFourth step - Configure NGINX You\u0026rsquo;ll need to create a config file for each of your services. LinuxServer.io provides a lot of example templates but here is a basic example of one of my config files. NGINX will have to be restarted after the changes.\nfruity.pebbels.conf\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 server { listen 80; listen [::]:80; server_name fruity.pebbels; client_max_body_size 0; location / { include /config/nginx/proxy.conf; include /config/nginx/resolver.conf; set $upstream_app 192.168.50.13; set $upstream_port 8989; set $upstream_proto http; proxy_pass $upstream_proto://$upstream_app:$upstream_port; } location ~ (/sonarr)?/api { include /config/nginx/proxy.conf; include /config/nginx/resolver.conf; set $upstream_app 192.168.50.13; set $upstream_port 8989; set $upstream_proto http; proxy_pass $upstream_proto://$upstream_app:$upstream_port; } } Configure Access Controls You\u0026rsquo;ll want to make sure that not just anyone connected to your Tailscale network can access your services. You can configure access controls to limit who can access what.\nGo to the Access Controls page https://login.tailscale.com/admin/acls/visual/general-access-rules Under the groups tab create a group for the users you want to give access and add the users. I just called my group NGINX so it\u0026rsquo;s easy to understand what it\u0026rsquo;s for. Go to the hosts tab and create a host for your NGINX container using the IP address of your NGNINX host listed on the machines page. Go to the general access rules tab Make sure you don\u0026rsquo;t already have a rule that gives access to all users. I had one by default that I limited to only my account. Create a new rule allowing access for only your NGINX group to the NGINX host. Success!! You should be all set. You can test by connecting to Tailscale on your device and accessing your custom URL like fruity.pebbels .\n","date":"2025-12-05T00:00:00Z","image":"https://cdn.chris-smith.net/homelab/tailscale/routing/banner.png","permalink":"https://chris-smith.net/posts/tailscale/","title":"TailScale Traffic Routing"},{"content":"This weekend marked four years since I’ve been with my partner, and it’s also the date we officially became husband and wife. We kept it simple: a quiet getaway to South Lake Tahoe with just the two of us.\nWe didn\u0026rsquo;t need someone to officianate our marriage; Becca had found online that California has a newer license that only requires witness\u0026rsquo;s to sign it. This license is meant to be more flexible for all kinds of religions and it really frees people up to celebrate how they want to. It\u0026rsquo;s so new that when we both picked up the license and dropped it off, the clerk had to check with their boss that the paper work was ok because they hadn\u0026rsquo;t seen it before.\nFriday: Thanksgiving breakfast, Tahoe arrival, and a tree lighting surprise We drove up the Friday after Thanksgiving and swung by my dad’s for Thanksgiving breakfast. We had spent Thanksgiving itself with other sides of our family, so it was a nice way to still see everyone before heading out.\nWe reached Tahoe around noon and had a couple of hours to kill before check-in, so we grabbed lunch at one of my favorite spots, Cafe Azule. They have Thai curry tacos that I have to get whenever I’m in Tahoe.\nAfter lunch we checked into the Desolation Hotel. Out of all our trips, this has been one of our favorite places to stay. We booked their townhome-style room, which ended up being a three-story mini-adventure all by itself. The first floor had a garage with an EV charger and storage. The second floor had the kitchen, living room, and a balcony. The third floor had the bedroom and master bathroom, plus a jacuzzi inside and a tub outside on the balcony. Every level had a fireplace you could enjoy from inside or from the balcony that we had going whenever we were there.\nLater that night we headed back out to Lake Tahoe Boulevard where all the shops are, and we accidentally stumbled into the Christmas tree lighting South Lake Tahoe was hosting that weekend. We got there right before the crowds started showing up so we had the perfect spot next to the tree.\nWe were also next to the street and ended up next to a firetruck rolled in with Santa and Mrs. Claus, and one of the firefighters went up the ladder to light the tree to a burst of fireworks.\nAfter the tree lighting we grabbed snacks and alcohol from the nearby Target and ended the night in the jacuzzi.\nSaturday: Cinnabon, a hike, and our celebration dinner Saturday started with Cinnabon for me and Starbucks to keep things moving. Then we headed to a trail that starts behind the South Lake Tahoe theater and follows the Heavenly gondolas up the mountain.\nA couple of miles in, there’s a rock where you can get a great view over South Lake Tahoe, and if you keep going you’ll eventually hit a waterfall. We’d hiked the trail in the past, but this was the first time we actually made it all the way to the waterfall.\nOn the way back, I started feeling pretty crummy. Becca pinpointed my symptoms as altitude sickness, which I didn’t even realize I could get. It probably didn’t help that the night before included alcohol and cooking ourselves out in the jaccuzi.\nFor our celebration dinner, we went down to the lake and ate at Jimmy’s at The Landing Resort \u0026amp; Spa. We ordered the Chilean sea bass, a lamb burger, and Hokkaido milk bread as an appetizer.\nIt was hilarious when the food came out. Becca got a full plate with a massive burger and sides followed by my plate with a small sliver of sea bass and potatoes where the food barely filled half the plate. The shock must have been written all over my face because the waiter immediately asked if everything was okay. Becca later confirmed I had a wtf look on my face when the food came out. Despite it looking like a small amount of food, it was still filling and tasted amazing.\nSunday: A slow day, Blue Dog Pizza, and a chilly pool mission By Sunday we were exhausted, and I still wasn’t feeling ok, so we leaned into a lazy day. We spent most of it in the room, only heading out when it was time to hunt down food.\nFor lunch we grabbed Blue Dog Pizza, and later we brought Cafe Azule back to the hotel for dinner. We ate and watched Train Dreams, a film about the life of a logger in 1917. It had never been on my radar, but we ended up loving it. It’s slower, but it holds your attention the whole time and feels like a really vivid window into that time period.\nAfter the movie, despite the freezing temperatures, we layered up to head outside to the pool.Becca had been wanting to use the pool at least once that weekend so it was our last chance to get that in. I wasn’t ready to deal with the cold, so I stayed bundled up poolside and played a few rounds of Hearthstone while Becca braved the cold air in her swimsuit.\nWe packed up before bed and headed out first thing Monday morning. It was a short trip but it was a nice romantic getaway.\n","date":"2025-11-29T00:00:00Z","image":"https://cdn.chris-smith.net/married/banner.png","permalink":"https://chris-smith.net/posts/married/","title":"Getting Hitched!"},{"content":"What is Pocket ID Pocket ID is a provider that handles logins using passkeys instead of passwords. It runs as an OpenID Connect (OIDC) provider, which means apps that support OIDC or external SSO can hook into it and let me log in securely without ever dealing with a username or password.\nResources Github: https://github.com/pocket-id/pocket-id\nDocumentation: https://pocket-id.org/docs\nGeolite key: https://www.maxmind.com/en/geolite2/signup\nPocket ID has an official Docker container in Apps in Unraid\nInitial Setup GeoLite Sign up on the linked site for a GeoLite database key. Without it, you won’t see IP locations in your logs. https://www.maxmind.com/en/geolite2/signup Log in to maxmind.com after your account is created Click Manage license keys Create license key Specify a name. I like to put the name of the container I’m using the key for Keep this page open so you can copy and paste the key into your container variable Container Setup Using the official Docker container in Unraid for this setup Search the Apps tab for Pocket ID to find it Kept most values at default except for the below Changed network type to a custom network for web‑facing containers Changed app URL Set Behind Proxy to true for NGINX Input MaxMind license key from earlier I kept the default SQLite database that’s part of the container. The only external database option Pocket ID works with is PostgreSQL, so it won’t work with my existing MariaDB database Submit and view container logs for any errors Proxy Setup I use SWAG from LinuxServer (link). As of this writing they don’t have a template NGINX config for Pocket ID, so we’ll be creating our own.\nSteps Copied proxy.conf and created a new file proxypocketid.conf Pocket ID’s documentation mentions needing larger proxy buffers than what’s in the standard proxy.conf file. Increasing those in the proxy.conf file could cause issues with other sites, so it’s better to just create a whole new config file Added the below proxy buffers to our new config file proxy_busy_buffers_size 512k; proxy_buffers 4 512k; proxy_buffer_size 256k; Removed the old proxy_buffers value Created a new NGINX config for Pocket ID. Example of my config is below. This config also includes the previous config file we created Restart the SWAG container and view the logs for any issues Nginx config files proxypocketid.conf\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 ## Version 2023/02/09 - Changelog: [https://github.com/linuxserver/docker-swag/commits/master/root/defaults/nginx/proxy.conf.sample](https://github.com/linuxserver/docker-swag/commits/master/root/defaults/nginx/proxy.conf.sample) # Timeout if the real server is dead proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; # Proxy adjustments per Pocket ID documentation proxy_busy_buffers_size 512k; proxy_buffers 4 512k; proxy_buffer_size 256k; # Proxy Connection Settings #proxy_buffers 32 4k; proxy_connect_timeout 240; proxy_headers_hash_bucket_size 128; proxy_headers_hash_max_size 1024; proxy_http_version 1.1; proxy_read_timeout 240; proxy_redirect http:// $scheme://; proxy_send_timeout 240; # Proxy Cache and Cookie Settings proxy_cache_bypass $cookie_session; #proxy_cookie_path / \u0026#34;/; Secure\u0026#34;; # enable at your own risk, may break certain apps proxy_no_cache $cookie_session; # Proxy Header Settings proxy_set_header Connection $connection_upgrade; proxy_set_header Early-Data $ssl_early_data; proxy_set_header Host $host; proxy_set_header Proxy \u0026#34;\u0026#34;; proxy_set_header Upgrade $http_upgrade; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Method $request_method; proxy_set_header X-Forwarded-Port $server_port; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-Ssl on; proxy_set_header X-Forwarded-Uri $request_uri; proxy_set_header X-Original-Method $request_method; proxy_set_header X-Original-URL $scheme://$http_host$request_uri; proxy_set_header X-Real-IP $remote_addr; Nginx Config\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 # Redirect HTTP → HTTPS (SWAG terminates TLS) server { listen 80; listen [::]:80; server_name [dashboard.chris-smith.net](http://dashboard.chris-smith.net); return 301 [https://$host$request_uri](https://$host$request_uri); } server { listen 443 ssl; listen [::]:443 ssl; http2 on; server_name [dashboard.chris-smith.net](http://dashboard.chris-smith.net); # SWAG SSL \u0026amp; security presets (HSTS, modern ciphers, etc.) include /config/nginx/ssl.conf; # Allow larger OIDC POSTs client_max_body_size 10m; location / { # SWAG proxy defaults: X-Forwarded-* headers, websockets, timeouts, etc. include /config/nginx/proxypocketid.conf; # Uses Docker DNS if SWAG runs in a Docker network include /config/nginx/resolver.conf; # Upstream to the Pocket ID container set $upstream_app 192.168.40.5; # container name or service DNS set $upstream_port 1411; # Pocket ID’s internal port set $upstream_proto http; proxy_pass $upstream_proto://$upstream_app:$upstream_port; } } Configure DNS Set up a static local DNS record Routes traffic internally without needing to go out to the internet Set up a DNS record in Cloudflare Routes traffic from the internet over Cloudflare tunnel Configuring Pocket ID Admin Account Setup Browse to https://{your-site-domain}/setup Enter your account information Add passkey Works with your password manager, browser, or hardware passkeys like YubiKeys Block signups page with NGINX Despite completing the initial admin setup and disabling the option for future users to go through the signup page, it was still visible. Blocking this page by adding the below location block to the Pocket ID NGINX config\n1 2 3 4 location /signup/setup { deny all; return 404; } Connect to email This will allow you to send login codes and login notifications to users.\nSetup Gmail Make sure you have MFA setup on your account before proceeding. Back in your MFA settings in Google security center scroll down to app passwords Set a name for your app, ie PocketID - \u0026gt; click create Copy that password and save for later Add email to PocketID Login to Pocket ID and go to Application Configuration Expand email Apply these settings SMTP Host: smtp.gmail.com SMTP Port: 587 or 465 for SSL SMTP Username: your email SMTP From: your email SMTP TLS Option: TLS Click save and test. PocketID will send a test email to the one you input. Setup your apps Before you start Visit yourpocketIDaddress.com/.well-known/openid-configuration\nThis page contains all of the information you\u0026rsquo;ll need to integrate PocketID with your services.\nRomm Romm documentation: https://docs.romm.app/3.8.3/OIDC-Guides/OIDC-Setup-With-PocketID/\nWhat is it Romm is an amazing browser‑based ROM and emulator application. It acts as a ROM management system pulling in metadata from different gaming databases and also lets you play most old ROMs in the browser.\nSetup Steps Pocket ID add OIDC client\nIn settings go to application configuration → tick “Emails Verified” OIDC Clients Click Add OIDC Client button Fill out Name and Client Launch URL Name: Romm Client Launch URL: https://{domain}/api/oauth/openid Click Save Make a note of the client ID and Secret. You won’t see it after the page refreshes Configure Romm container\nI already had a container so I added these variables to my existing one.\nAdd these environment variables to the romm container OIDC_ENABLED: true OIDC_PROVIDER: pocketid OIDC_CLIENT_ID: client id saved from pocket id OIDC_CLIENT_SECRET: client secret saved from pocket id OIDC_REDIRECT_URI: https://{domain}/api/oauth/openid OIDC_SERVER_APPLICATION_URL: https://{pocket ID URL} NOTE!! This differs than ROMM’s documentation. Using /authorize at the end of the domain gave me a 200 error. Submit and view the logs for any errors Configure Romm\nMake sure email for your email address matches the email used in Pocket ID Test\nRomm now shows an option to log in with Pocket ID in addition to the typical username/password NextCloud Enable OpenID Connect Login\nNextcloud → Apps → Integration → OpenID Connect Login (official) Click allow untested app if it says that Followed by Download and enable Browse to this URL and save the information for later\nhttps:///.well-known/openid-configuration\nConfigure PocketID\nGo to pocketID → Settings OIDC Clients Add OIDC client Settings to configure Name = Nextcloud Client Launch URL = https://nextcloud.smithc.net Callback URL = https://nextcloud.chris-smith.net/apps/oidc_login/oidc Logout Callback URL = https:///index.php/logout Click Save → don’t close this page! Save Client ID \u0026amp; Client Secret for later Configure Nextcloud\nIt’s time to input all of the information we’ve saved into Nextcloud’s config.php file\n1 2 3 4 5 6 7 8 9 10 11 12 13 \u0026#39;oidc_login_provider_url\u0026#39; =\u0026gt; \u0026#39;[https://pocketid.chris-smith.net](https://pocketid.chris-smith.net)\u0026#39;, \u0026#39;oidc_login_client_id\u0026#39; =\u0026gt; \u0026#39;nextcloud\u0026#39;, // replace with your client ID \u0026#39;oidc_login_client_secret\u0026#39; =\u0026gt; \u0026#39;YOURSECRET\u0026#39;, \u0026#39;oidc_login_end_session_redirect\u0026#39; =\u0026gt; true, \u0026#39;oidc_login_scope\u0026#39; =\u0026gt; \u0026#39;openid profile email\u0026#39;, \u0026#39;oidc_login_match_email\u0026#39; =\u0026gt; true, \u0026#39;oidc_login_attributes\u0026#39; =\u0026gt; [ \u0026#39;id\u0026#39; =\u0026gt; \u0026#39;sub\u0026#39;, \u0026#39;name\u0026#39; =\u0026gt; \u0026#39;name\u0026#39;, \u0026#39;mail\u0026#39; =\u0026gt; \u0026#39;email\u0026#39;, ], \u0026#39;redirectUri\u0026#39; =\u0026gt; \u0026#39;[https://nextcloud.chris-smith.net/apps/oidc_login/oidc](https://nextcloud.chris-smith.net/apps/oidc_login/oidc)\u0026#39;, \u0026#39;autoRedirect\u0026#39; =\u0026gt; \u0026#39;true\u0026#39;, I enabled account creation based on PocketID login by running the below command in the Unraid terminal\n1 docker exec Nextcloud php occ config:system:set oidc_login_disable_registration --value=false --type=boolean Nextcloud should now have an OpenID Connect button that redirects to PocketID for authentication. If a user doesn’t exist it creates one.\nTroubleshooting Logs Romm logs\n1 docker logs -f romm ","date":"2025-10-05T00:00:00Z","image":"https://cdn.chris-smith.net/homelab/pocketid/banner.png","permalink":"https://chris-smith.net/posts/pocketid/","title":"OIDC - PocketID"},{"content":"What is a custom network A custom network is a docker network that is bridged to a physical Unraid interface or VLAN interface on the host. In this use case we’ll be setting up an ipvlan where all containers will have different IPs but share the same host MAC address. This was done to avoid issues with MacVLANs in older Unraid versions and to keep it consistent with my other custom networks.\nUse case We’re creating an isolated VLAN for containers that should be extra locked down, like databases. Only specific services will be granted access to containers on this network using firewall rules and this network will also be blocked from access to the internet. Since containers are updated on the Unraid host itself and they’re just databases, blocking internet access should have no affect on anything.\nCreating a new VLAN in Unifi Login to your Unifi network by browsing to it’s IP\nGo to Settings → Networks → New Virtual Network VLAN 8 Secure network setup in Unifi\nFill out the following details\nName: Secure Host Address: 192.168.80.1 I keep the netmask of 24 the same This will auto populate other fields such as Gateway IP VLAN ID: 8 Check only Isolate network so firewall rules are automatically created to block my other VLANs from accessing this. Future firewall rules can be created to poke holes and let other services access containers on this network. Uncheck all boxes including internet access in this use case. Containers on this network have no need to connect to the internet and if they did that’s because they’ve probably been compromised. Container updates are also done on the Unraid host itself so they won’t be blocked from upgrades. DHCP off , I like to specify my own static IPs when creating containers. I keep my static IPs documented in Google Docs to prevent conflicts. Unraid will stop you if you do try to take an IP you’ve already used. Firewall rules that were automatically created\nFirewall rule details blocking access between VLANs\nCreating an ipvlan network in Unraid I like to use an ipvlan network for Unraid because I can control access via my Unifi network system\nDisable Docker and VM Manager I like to stop all containers and VMs manually first before disabling the services in the Unraid settings. Disable docker Settings → Docker Enable Docker → set to no → click apply Disable VMs Settings → VM Manager Enable VMs → set to no → click apply Add the VLAN in Unraids network settings Go to network manager and next to enable VLANs make sure it’s marked yes, then click the show button Click ADD VLAN Fill out the new VLAN info Interface description: Secure VLAN Number: 8 Network protocol: IPv4 only IPv4 address assignment: none Click Apply Visual of the new VLAN settings in Unraids network settings\nAdd the network to the Unraid docker settings Settings → docker Docker should still be disabled Docker custom network type should be ipvlan At the bottom of the page you should see our new interface and in this case it’s br0.8 and it’s disabled. Subnet: 192.168.80.0 Gateway: 192.168.80.1 Click Apply. You should now see a new custom ipvlan network (br0.8) appear as a dropdown option when creating containers. Visual of network settings for docker\nBring everything back online Re-enable docker Settings → Docker Enable Docker → set to yes → click apply Containers should auto-start if that is enabled Re-enable VMs Settings → VM Manager Enable VMs → set to yes → click apply VMs should auto-start if that is enabled ","date":"2025-09-01T00:00:00Z","image":"https://cdn.chris-smith.net/homelab/customnetwork/banner2.png","permalink":"https://chris-smith.net/posts/homelab-customnetwork/","title":"Home Lab - Custom Network"},{"content":" Day 6 Les Trois CascadesWe start the morning off by pulling out the kayaks and taking a swim before eventually heading north just past Papeete to Les Trois Cascades. A small hike with multiple large waterfalls. Les Trois Cascades On the way back to the our Airbnb we stop by the same food trucks we had the night before for dinner before settling in for a lazy night. Day 7 Back to PapeeteAfter packing up and leaving the Airbnb we had a lot of time to kill before our flight. We head up to Papeete to explore the city and pickup gifts for our families and friends. Papeete Waterfront Heading homeHeading home Coolest place to park it at the airport Boarding our plane ","date":"2025-08-02T00:00:00Z","image":"https://cdn.chris-smith.net/tahiti2025/part3/postbanner.jpg","permalink":"https://chris-smith.net/posts/tahiti2025p3/","title":"Tahiti Part 3"},{"content":"Day 5 had arrived and we planned to go out on a waterfall hike. I\u0026rsquo;d been waiting for the waterfall hike to propose and had already been carrying the ring in my pocket for a couple of days.\nThis trip wasn\u0026rsquo;t just about getting away but it was also about the proposal. Before we had decided on Tahiti I had originally wanted New Zealand. Aside from it being gorgeous it\u0026rsquo;s also the place Lord of the Rings was filmed which is Becca\u0026rsquo;s favorite movie series. That plan feel through and my fallback was going to be the island of Mo\u0026rsquo;orea which was a short ferry ride outside of Tahiti. Mo\u0026rsquo;orea eventually feel through because we didn\u0026rsquo;t plan to stay there and the ferry times only ran until 2pm. I\u0026rsquo;d picked out a specific beach and private dinner at a resort but I had no idea just how early things closed down in Tahiti.\nSo the fall back plan was the water fall hike. We made our way south on the main road and circled the island counter clockwise for about 40 minutes. Just as we\u0026rsquo;re 5 minutes away from the trail head, we hit a road closure! The storm from the previous couple of days had caused massive mud slides and had closed down this portion of the road blocking our way!\nWith my plans foiled once again Becca mentions we should backtrack to a waterfall we\u0026rsquo;d seen while driving that was right off the road. With some luck we get there and the only other people was a family who was already leaving. We had the falls to ourselves. When parking there was a sign in French that mentioned the area was a private property that listed hours the public could visit. We translated the sign and determined it was ok for us to go in. However while walking to the falls Becca was Googling a nearby trail next to the falls and in Google the trail said it was closed!\nSo while I\u0026rsquo;m planning my moves to mount my camera and capture the proposal on video, Becca starts freaking out that we\u0026rsquo;re trespassing and wants to leave. I of course with my hands up stop her and keep re-iterating no it\u0026rsquo;s ok lets just get our photo at the falls first. I set my phone on the ground and pretend to be trying to connect to it with my watch to take the photo. Meanwhile I\u0026rsquo;m reaching for the ring in my pocket. Becca was so distracted with wanting to leave and confused by my commotion, when I kneeled, she also started to kneel! She quickly did realize what was happening and said yes!\nNo Trespassing!\nWe finish off the night with another beach sunset before grabbing myself some crepes and Becca a pizza from Le Foodcourt\nBeach Sunset\nLe Crepuscule food truck\n","date":"2025-07-31T00:00:00Z","image":"https://cdn.chris-smith.net/tahiti2025/part2/banner.png","permalink":"https://chris-smith.net/posts/tahiti2025p2/","title":"Tahiti Part 2: Proposal"},{"content":" Day 1 ArrivalWe landed in Tahiti around 9 PM local time after a 9.5-hour flight and deplaned right onto the tarmac — a unique and memorable welcome. Customs took about an hour, and then we grabbed our bags and stepped directly into the warm evening air. We picked up a 5-speed Peugeot 208 — a tiny 1.2 L with barely any power, but surprisingly fun to drive. The maintenance light was on from the start, which was a little concerning, but it never caused issues (probably just from previous drivers abusing the clutch as much as I did). Our tiny Peugeot 208 McDonaldsStarving after the long flight, we stopped by McDonald’s on the way to the Airbnb. Their local specialty is the “Boss Burger,” basically a Quarter Pounder served on Hawaiian bread. McDonalds Settling InAnother 20-minute drive brought us to the Airbnb, where our host, Eda, gave us a quick tour and made us feel at home before we crashed for the night. Villa TEIPO Day 2 Market RunFor our first morning, we headed to LS Proxi to stock the Airbnb with drinks and snacks. Being a French territory, Tahiti is full of fresh baguettes — you’ll see bins of them at every store and people casually walking or biking with one in hand.\nBack at the Airbnb, we had breakfast in the backyard with a view of the ocean. Becca made a charcuterie board from our haul — simple but perfect.\nBreakfast with a view Snorkeling the ReefThe ocean was so clear we couldn’t resist jumping in. We grabbed the inflatables and snorkels our friends lent us and headed into the reef. Without water shoes, though, we kept getting pushed into the coral by the current. Combined with the low tide (just a few feet deep), we left the water after a few hours with scraped ankles and knees. Crystal-clear waters Fishes Pizza TraditionOn all our trips, we try at least one local pizza spot — a tradition that started years ago while camping in Chester. Our first Tahitian pizza was at Frero Della Pizza: a large pepperoni, pineapple, and olive pie that ended up being my favorite of the trip. Frero Della Pizza Sunset Dinner Sunset Dinner Good Night Sunset Day 3 Morning PastriesWe started off our morning by walking 10 minutes to a nearby bakery, Le Passionné. This place was amazing — I had a strawberry-and-cream pastry (the one in my photo), while Becca raved about the croissants and even tried a hot-dog pastry (which her stomach regretted after a second breakfast). Le Passionné Bakery Exploring Grotto De Mara’aWe started off our morning with a brief swim and attempt at taking the kayaks out before driving 20 minutes to Grotto De Mara’a — our first “hike” of the trip. The grotto features three freshwater caves filled with mountain runoff. You can technically swim there, but we didn’t see anyone try. There’s also a steep rope-assisted trail nearby, but we passed on it this time. Grotto De Mara Grotto De Mara Foodcourt DinnerDinner that night was our farthest drive yet — to Le Foodcourt Punaauia. I got a chicken burrito but in Tahiti they were called a Tiapai Tacho and Becca got gyro but known in Tahiti as a Le Chiche. Both were really good. We’d come back later in the trip when Becca found her favorite pepperoni pizza of the entire vacation. Le Foodcourt Let me in! Stormy Drive HomeOn the way back, the biggest storm of the trip hit. Heavy rain flooded the roads and dropped visibility to near zero\nThis little guy was wanting in the next morning\nLet me in! Day 4 Chasing the SunThe storm rolled into our fourth day, so there were no morning swims this time. Becca, who had been monitoring the weather patterns all trip, noticed that the northern part of the island was completely sunny. We made our usual stop for energy drinks and snacks and then drove about 40 minutes north to Papeete — the island’s largest city and the place where we saw the most tourists. Heading to Papeete Exploring Papeete MarketWe first stopped by the Papeete Market which is considered to be one of the must visit places for tourists. Papeete Market Black Pearl StopAfter leaving the market, we explored more of the city and stopped at a small jewelry store where Becca picked out a black pearl to take home. Black Pearl Necklace Boba BreakSweaty and tired, we spotted a boba shop on the way back to the car and couldn’t resist stopping. The employees were speaking rapidly in French, and one gave a dramatic stink face when my brown sugar milk tea order was relayed — which made me wonder if something might be off with my drink! They also sold mochi, and I had one filled with strawberries and cream — basically a strawberry shortcake mochi — one of the best mochi desserts I\u0026rsquo;ve ever had. Boba in Papeete Ahonu BeachWith drinks in hand, we drove about 10 minutes north to Ahonu Beach. After a few laps in a roundabout (and cutting someone off — sorry Becca!), we finally arrived. We relaxed by the water for a while, but after a full day of exploring Papeete we were completely wiped out. On the way home, we grabbed another round of Le Foodcourt for dinner before crashing at the Airbnb. Black sand vibes Tsunami AlertThat night, an 8.8 earthquake hit Russia, triggering a tsunami alert across the entire Pacific — including Tahiti. Combined with the ongoing heavy rainstorm. Thankfully, by morning the alert was lifted, the rain had stopped, and the skies cleared. Earthquake in Russia and Tsunami Warning ","date":"2025-07-26T00:00:00Z","image":"https://cdn.chris-smith.net/tahiti2025/part1/banner.jpg","permalink":"https://chris-smith.net/posts/tahiti2025p1/","title":"Tahiti Part 1"},{"content":"👋 Hello! Welcome to my blog / personal website. If you have already guessed from the URL - which I was pretty lucky to snag (chris-smith.net) - I’m Chris. I created this site to record and share the various projects I might be working on or things that I’m learning. It’ll help chart my growth in different areas but also be a cool little time machine to look back. Over the years, I’ve worked on tons of projects that were eventually scrapped — and I regret not saving anything to look back on. But it’s not all work — this will also be a spot to share travels, games, or movies I’m currently obsessed with.\nThank you for dropping by and skimming what I’ve written. If you’re curious of what cool tech I’m playing with for this site continue reading!\nHugo This website is built using Hugo which is a website framework written in Go. I love the simplicity Hugo brings when compared with sites like Wordpress, Ghost, or Squarespace.\nCloudflare Pages https://pages.cloudflare.com\nIt’s free!!! Cloudflare is an amazing platform that offers a lot of tools for home lab enthusiasts that are free and enhance security for your hosted services. They offer a service for hosting static websites (supports Hugo) for free and you can point your own custom domain to it. Another cool thing is you can point it to Github so any change to your sites code is automatically recompiled and displayed on the website.\nGoogle IDX / Firebase Studio https://studio.firebase.google.com/\nThis is a really cool tool that is basically an IDE in your browser that has AI (Google Gemini) and version control built in. It also has a terminal so even though my code is remotely on that site I can still run hugo server -D and preview the changes I made to my website temporarily.\nThe builtin AI works really well. I can ask it a question like “why is this still black” and it’ll go through all of the project files and give an explanation to why it’s black as well as a possible fix. This has really helped me save time and track down something that might be buried that I might never have found. It also has a cool ability for all of the “vibe coding” that’s trending. You can start off your coding project with a prompt and Google IDX (Firebase now) will present to you a blueprint breaking down everything you requested. You have the ability to ask the AI to modify the blueprint. Once you’re satisfied with the blueprint and click go, the AI starts coding all of the files it thinks you need.\nI’m planning a future project where I want to prompt for a chess teaching application. I want the ability to modify the pieces and board with my own sprites and have AI integration by having the user supply an API key for their AI of choice\nProjects in the pipeline Some projects I’m currently working on that I may blog about in the near future\n🤖Chess application: try my hand at “vibe coding” which is prompting ai to code an application. For this I’m looking to have the ability to use my own custom sprites for chess pieces and board that can be swapped out easily as well as have ai integration. 🎮 Adventure Land MMORPG: A game a wish I had as a kid and wish I had found sooner since it hasn’t been updated in 2 years. It’s a top down MMO similar to Ragnarok, but the idea behind it is you code your character or characters (you can run multiple at the same time) actions. Currently I have grouping and follow logic done but I’m excited to expand that. ","date":"2025-04-15T00:00:00Z","permalink":"https://chris-smith.net/posts/hello-world/","title":"Hello World!"}]