<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: James Newman</title>
    <description>The latest articles on Forem by James Newman (@jam3sn).</description>
    <link>https://forem.com/jam3sn</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F946500%2Fc047a497-4835-4868-8538-e695bfed3700.jpeg</url>
      <title>Forem: James Newman</title>
      <link>https://forem.com/jam3sn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jam3sn"/>
    <language>en</language>
    <item>
      <title># My Homelab: 2022 A year in review</title>
      <dc:creator>James Newman</dc:creator>
      <pubDate>Thu, 29 Dec 2022 11:18:54 +0000</pubDate>
      <link>https://forem.com/jam3sn/-my-homelab-2022-a-year-in-review-30o3</link>
      <guid>https://forem.com/jam3sn/-my-homelab-2022-a-year-in-review-30o3</guid>
      <description>&lt;p&gt;&lt;em&gt;This article is also available &lt;a href="https://jamesnewman.dev/blog/homelab-review-2022/" rel="noopener noreferrer"&gt;on my blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;2022 has truly been my year of homelabbing, with learning, iteration and change being a reoccurring theme. I began the year with a somewhat humble homelab, and while I’m not ending it with anything outrageous, it has certainly come a long way. Looking into the next year, I &lt;em&gt;plan&lt;/em&gt; on less hardware changes, but there’s certainly a lot more to learn.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it started
&lt;/h2&gt;

&lt;p&gt;I began 2022 with a Synology DS720+ as my file and Plex server, a Dell Optiplex small form factor PC as an application server and the Unifi Dream Machine (UDM) for my router. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feqdz3invisv6j05scpwh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feqdz3invisv6j05scpwh.png" alt="Homelab at the start of the year" width="800" height="600"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Yes that’s a Makita belt sander and a car cleaning kit behind, storage is tight in this apartment 😅&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The Synology is a great little machine, and while pricier than their competitors, the hardware and software quality makes up for the price difference.&lt;/p&gt;

&lt;p&gt;The Dell Optiplex is a low power, small form factor PC with a 6 core i5-9500T, 16GB RAM, 256GB NVME SSD and a 1TB SATA SSD. Bought fairly cheap on eBay, these are a common choice for low power and low budget homelabs. For me it was essentially a docker box. I started on Ubuntu server, but quickly swapped to Proxmox and then an Ubuntu VM. While it was a good little machine, the single NIC was becoming a bottle neck along with the lack of cores / threads. And so I sold this in the summer, but in hindsight wish I’d kept it.&lt;/p&gt;

&lt;p&gt;Finally, the Unifi Dream Machine, UDM from here on, is a good little router and certainly a nice upgrade from your ISP or run of the mill (insert brand name) router. However, I have certainly run into some issues with it and has me considering a pfSense box.&lt;/p&gt;

&lt;h2&gt;
  
  
  The big upgrade
&lt;/h2&gt;

&lt;p&gt;I mentioned above I sold my Optiplex in the summer, replacing this was my new custom built &lt;em&gt;“server”&lt;/em&gt;. With more RAM, cores, storage and expandability. This new server also managed to change two more times before arriving at the current configuration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbg8t7ethdr7o1ktnz0kw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbg8t7ethdr7o1ktnz0kw.png" alt="New server parts" width="800" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Initial Specs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU: Intel i7-10700&lt;/li&gt;
&lt;li&gt;RAM: 32GB Corsair Vengeance LPX 3200&lt;/li&gt;
&lt;li&gt;Motherboard: MSI MAG B560M Mortar&lt;/li&gt;
&lt;li&gt;SSD: 2TB Samsung 980 Pro&lt;/li&gt;
&lt;li&gt;PSU: BeQuiet Pure Power 11 400w&lt;/li&gt;
&lt;li&gt;CPU Cooler: BeQuiet Shadow Rock LP&lt;/li&gt;
&lt;li&gt;NIC: Intel I350 T4&lt;/li&gt;
&lt;li&gt;Case: Fractal Node 804&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The CPU has 8 cores, 16 threads, it’s 65W TDP (not “K” series), and importantly for me, supports Intel QuickSync - Intel's video encoder, supported by applications like Plex and Handbrake.&lt;/p&gt;

&lt;p&gt;I opted for a consumer motherboard and RAM, being much cheaper than server hardware and sufficient for my use cases. This freed up some budget for the Samsung 980 Pro, a solid NVME SSD for fast and reliable storage.&lt;/p&gt;

&lt;p&gt;The case was purchased very cheap second hand from a friend and did the job nicely, for now…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkga0jxvs0d0tt00vt8ub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkga0jxvs0d0tt00vt8ub.png" alt="New server in situ" width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My idea for this new server was to replace my Synology and the Optiplex. It would be my file server, Plex server, a small Minecraft server for friends and a Docker host.&lt;/p&gt;

&lt;p&gt;I had played with Unraid and TrueNAS but encountered a number of issues with both, so eventually ended up going back to my Synology as my primary file server. The Minecraft server also didn’t go to plan, but not from a lack performance. I didn’t want to port forward and so used FRPC to proxy though a Linode VPS, however the latency was too much for my friend on the other side of the planet.&lt;/p&gt;

&lt;p&gt;So, the new server became a somewhat overpowered Docker host, running Proxmox with a few VMs, using Ubuntu as the Docker host.&lt;/p&gt;

&lt;h3&gt;
  
  
  Iteration 2
&lt;/h3&gt;

&lt;p&gt;The case was a little large and bulky for the space it was in. I also didn’t need the 3.5” bays now I had switched back to my Synology. Additionally I was after a 5.25” bay for a blu-ray reader. While the fractal supports slim slot readers, I wasn’t able to find one that would support the custom firmware to rip (backup) my UHD blu-ray collection. So I switched to the Silverstone GD09, a compact case with support for a 5.25” and fitted in my shelving unit. It’s worth noting the sides of this unit is mesh, so the server had plenty of airflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1e33va0lom26zx4ehgut.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1e33va0lom26zx4ehgut.png" alt="Iteration 3 in situ" width="360" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also needed to add a PCI SATA card in order to pass through the SATA controller to the Windows VM in order to use the blu-ray drive with it. Paired with MakeMKV, I was ripping and backing up my blu-ray collection. On occasion MakeMKV would no longer find the drive, but shutting down the sever and power cycling resolved this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Iteration 3 (The current configuration)
&lt;/h3&gt;

&lt;p&gt;After much consideration and a little convincing from a friend, I decided to give Unraid another chance. With only two bays on my Synology, I needed more storage capacity and with Synology moving to AMD CPUs across their new line up, a new NAS was out of the question. &lt;/p&gt;

&lt;p&gt;I decided to rebuild my server in yet another case, this time with the Fractal Refine R5. The plan was to rehouse the server in the cupboard that was its original home. However, this time I purchased a shelving rack that would better fit the awkward space.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F004m0fzajwwdk57pzvta.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F004m0fzajwwdk57pzvta.png" alt="Iteration 3 angled" width="427" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11skji9ob1euxodzh3sl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11skji9ob1euxodzh3sl.png" alt="Iteration 3 side on" width="577" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Not in situ&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This time the Unraid setup and configuration went a lot more smoothly, although I did have some issues (from user error) setting up a bond with the 4 NICs on the Intel network card. Finally I setup the 4 NICs in a round robin balancer bond (balance-rr) configuration.&lt;/p&gt;

&lt;p&gt;I was also able to take out the PCI SATA card and use the MakeMKV docker image in Unraid, passing the device path instead of a SATA controller.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Over the last few months of running Unraid I have really dialled in the configuration to work for me. All of my app data is stored on the SSD, making docker images and VMs blazing fast, while allowing the HDDs to spin down. The rest of my files are spread across these hard drives and for now a single parity drive.&lt;/p&gt;

&lt;p&gt;For the most part I am using the Unraid docker interface, although this can be a little lacking for more complicated configurations where the use of Docker Compose would simplify things. Portainer may fill in the blanks here for some people, however I just span up a minimal Ubuntu server in a VM to run docker for these specific use cases.&lt;/p&gt;

&lt;p&gt;I have set up a local Nextcloud to replace Synology drive for syncing smaller files like documents across my computers and devices. I do need to better utilise its other features like the Calendar and Contacts if I hope to further replace cloud services like iCloud. I still use SMB shares for larger files like backups and media.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other changes and improvements
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Networking
&lt;/h4&gt;

&lt;p&gt;This year I also began to step further into networking! With help from a friend I setup VLANs on my network, purchased some managed Netgear switches and segmented my network appropriately. This coincides with some firewall configuration and also helped me configure a VPN server for remote connections to my home network when I am out and about.&lt;/p&gt;

&lt;p&gt;While I’ve done all this on the UDM, I can’t help but feel that Unifi makes some of this configuration long winded and trickier than it should be. In addition, there are known problems like not being able to create a firewall rule preventing VPN clients from accessing the controller. I am hopeful that the new controller OS update will resolve some of my bugbears. Failing that, a switch to pfSense is almost inevitable.&lt;/p&gt;

&lt;h4&gt;
  
  
  Raspberry Pis
&lt;/h4&gt;

&lt;p&gt;I played a little with the Raspberry Pi this year, creating a small cluster to learn Kubernetes. This was a super cool little setup with a fancy cluster case and all, but I just wasn’t using it. Like the Optiplex, I sold them on at a fair price to a friend. However, I intend to revisit the Pi moving PiHole from the sever to a Pi, along with my reverse proxy, NUT (a network UPS server) and potentially a second Pi for redundancy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F06p7waynyz3vg52t2xh0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F06p7waynyz3vg52t2xh0.png" alt="Pi Cluster in a 10” Rack" width="381" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Currently, if the Unraid server is offline for any reason, devices are unable to resolve the DNS as it’s hosted on the server. &lt;em&gt;“Well setup a second DNS entry in your router!”&lt;/em&gt; I hear you cry. It would seem doing so results in my devices using this second DNS entry to resolve domains in my PiHole blacklist, rendering the PiHole useless…&lt;/p&gt;

&lt;p&gt;I also tried the Pi TV hat, allowing me to receive digital DVB-T2 signals, a bit like the HD Homerun, but seemingly worse… I had a great deal of issues configuring, receiving and streaming live TV with the Pi TV hat. The tuner seemed hit and mis on whether it’d find channels that my TV would otherwise pick up when plugged-in directly to the buildings antenna. I tried a signal booster which did improve my results, but still found lacking.&lt;/p&gt;

&lt;h4&gt;
  
  
  UPS
&lt;/h4&gt;

&lt;p&gt;After putting it off for a long time, I finally have a UPS. I originally ordered an Eaton Eclipse 500, which the product photos on Amazon showed a USB for management, however this model didn’t include a USB management port. I ended up keeping this UPS and eventually ordering a second, the 650 &lt;strong&gt;with&lt;/strong&gt; USB. Now if the power goes out, my server and NAS can gracefully shutdown. &lt;/p&gt;

&lt;h4&gt;
  
  
  Synology
&lt;/h4&gt;

&lt;p&gt;The Synology still has its uses in my homelab, primarily acting as a backup server using some of their great apps. Synology Photos has become my tool of choice for backing up and viewing my photo library from my phone across devices. Active Backup allows me to backup appdata, files and media from my Unraid server via SMB. And finally I use Hyper backup to then backup the most important files to Synology C2 for offsite backups.&lt;/p&gt;

&lt;h4&gt;
  
  
  All together
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foccu22epgtym9iksgq0x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foccu22epgtym9iksgq0x.png" alt="Iteration 3 in situ" width="327" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Capping off the year
&lt;/h2&gt;

&lt;p&gt;So, as you can see, there have been plenty of changes this year and I have certainly learned a lot. But going forward there’s a number of things I plan to change in 2023:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a Unifi Wifi AP, the UDM Wifi is patchy at best.&lt;/li&gt;
&lt;li&gt;Implement monitoring for my servers and containers.&lt;/li&gt;
&lt;li&gt;Replace NGINX Proxy Manager with Traefik.&lt;/li&gt;
&lt;li&gt;Expose limited access to services like Plex via Tailscale funnel.&lt;/li&gt;
&lt;li&gt;Potentially replacing my UDM with a pfSense box.&lt;/li&gt;
&lt;li&gt;Potentially replace my Ikea smart lights and hub with Phillips Hue - I have to restart this thing multiple times a week for it work in HomeKit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m also really interested in finding ways to reduce my homelab's power usage. I am by no means an eco warrior, but certainly notice the increase on my power bill here in the UK this year. Combined with smaller form factor systems, I really feel the lower power / small form factor homelab community is pushed side in favour of big, power hungry server racks.&lt;/p&gt;

&lt;p&gt;And finally, more guides and blog posts! Stay tuned.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article is also available &lt;a href="https://jamesnewman.dev/blog/homelab-review-2022/" rel="noopener noreferrer"&gt;on my blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>learning</category>
    </item>
    <item>
      <title>Accessing a Unifi network over VPN</title>
      <dc:creator>James Newman</dc:creator>
      <pubDate>Tue, 15 Nov 2022 18:43:05 +0000</pubDate>
      <link>https://forem.com/jam3sn/accessing-a-unifi-network-over-vpn-49om</link>
      <guid>https://forem.com/jam3sn/accessing-a-unifi-network-over-vpn-49om</guid>
      <description>&lt;p&gt;&lt;em&gt;This article is also available &lt;a href="https://jamesnewman.dev/blog/vpn-on-unifi/"&gt;on my blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this post I'm going to walk you through how I setup my VPN server on the Unifi Dream Machine, and it'll likely be the same for the Dream Machine Pro or Security Gateway.&lt;/p&gt;

&lt;p&gt;I have a few services running in my homelab that I'd like to access when I'm not home, such as Plex and Nextcloud. But exposing these to the open web can be risky and a bit scary. Even though I have my network nicely segregated into VLANs, &lt;em&gt;(big thanks to my friend Blag for assisting)&lt;/em&gt;, and could use a proxy tool like &lt;a href="https://github.com/fatedier/frp"&gt;FRP&lt;/a&gt; or &lt;a href="https://www.cloudflare.com/en-gb/products/tunnel/"&gt;Cloudflare tunnels&lt;/a&gt; to avoid opening ports, it's still risky. Of course setting up a VPN server isn't bullet proof, but it is &lt;em&gt;less&lt;/em&gt; risky. In fact, if you're working remotely there's a good chance you're using a corporate VPN on your work computer to connect to their systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backup
&lt;/h3&gt;

&lt;p&gt;Before we change any settings on the router I'd suggest creating a backup of your current configuration. Nothing &lt;em&gt;should&lt;/em&gt; go wrong, but I've learnt the hard way from accidentally locking myself out of my managed switch that it's good to have a rollback point. You can do this from the Unifi OS System settings right after you log in, before selecting the network - Settings &amp;gt; System &amp;gt; Cloud Config Backup &lt;code&gt;https://[your_gateway_ip]/settings/system&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bPyIzmn3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_800/v1668448481/udm-vpn-backup_hnpd8g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bPyIzmn3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_800/v1668448481/udm-vpn-backup_hnpd8g.png" alt="Unifi OS &amp;gt; Settings &amp;gt; System &amp;gt; Cloud Config Backup" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a new backup and then download it. You should have a download similar to &lt;code&gt;unifi_core_backup_[some_string].unifi&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  VPN Server Configuration
&lt;/h3&gt;

&lt;p&gt;Go ahead and click into your Unifi network &amp;gt; Settings &amp;gt; Teleport &amp;amp; VPN &lt;code&gt;https://[your_gateway_ip]/network/default/settings/vpn&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now Unifi does have a zero configuration VPN "Teleport", however access with this is limited. You'll need to use the WiFiman app on mobile, and desktop... well as of writing this the macOS app is "coming soon" and there's no support for Windows.&lt;/p&gt;

&lt;p&gt;We're going to opt for the traditional VPN server further down on the page. So check the enable VPN Server box and we can start entering our settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wQEvS6Ep--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_800/v1668449603/udm-vpn-server-settings_hbsuqt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wQEvS6Ep--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_800/v1668449603/udm-vpn-server-settings_hbsuqt.png" alt="Unifi Traditional VPN settings" width="800" height="928"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fields of note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pre-shared Key - You'll need this later when connecting, I added it to my password manager with the username and password further down.&lt;/li&gt;
&lt;li&gt;User Authentication.&lt;/li&gt;
&lt;li&gt;Network Name - This will show in the network column of the "Clients" page in the Unifi Network along with the username connected.&lt;/li&gt;
&lt;li&gt;Gateway/Subnet - This is the Subnet / IP range you want your VPN clients to be on. I'd recommend setting the network size as small as you require, such as 29 (5 IPs).&lt;/li&gt;
&lt;li&gt;Require Strong Authentication - It may cause issues for some devices, but I've not encountered this so far.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's worth noting the VPN cannot be on a VLAN, nor can it be in a VLANs IP range. However we can still configure firewall rules with groups, which we'll cover further down.&lt;/p&gt;

&lt;p&gt;With those configured, your VPN server should be ready. You'll connect shortly via your public IP, but I would recommend using a DDNS (dynamic domain name system) if you don't have a static IP like me. My &lt;a href="https://kb.synology.com/en-global/DSM/help/DSM/AdminCenter/connection_ddns?version=7"&gt;Synology NAS has a service built-in&lt;/a&gt; for this, but there's many others out there including &lt;a href="https://www.duckdns.org/"&gt;DuckDNS&lt;/a&gt; and &lt;a href="https://developers.cloudflare.com/dns/manage-dns-records/how-to/managing-dynamic-ip-addresses"&gt;Cloudflare&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting
&lt;/h3&gt;

&lt;p&gt;Now we have our VPN server running, lets try connecting! I'll be connecting from an iPhone and mac. But here's steps for &lt;a href="https://support.google.com/work/android/answer/9213914?hl=en"&gt;Android&lt;/a&gt; and &lt;a href="https://support.microsoft.com/en-us/windows/connect-to-a-vpn-in-windows-3d29aeb1-f497-f6b7-7633-115722c1009c"&gt;Windows&lt;/a&gt;, the steps below should give you an idea.&lt;/p&gt;

&lt;h4&gt;
  
  
  iPhone
&lt;/h4&gt;

&lt;p&gt;From settings, either search for VPN, or go to General &amp;gt; VPN &amp;amp; Device Management &amp;gt; VPN &amp;gt; Add VPN Configuration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A17E103e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_400/v1668457648/udm-vpn-iphone_gzgmpt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A17E103e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_400/v1668457648/udm-vpn-iphone_gzgmpt.png" alt="iPhone VPN Configuration" width="400" height="865"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Mac
&lt;/h4&gt;

&lt;p&gt;From settings, either search for VPN, or go to Network &amp;gt; Three dot button in the bottom right &amp;gt; Add VPN Configuration &amp;gt; L2TP over IPSec.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CQkgdtHa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_800/v1668458381/udm-vpn-mac_hjv6iq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CQkgdtHa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_800/v1668458381/udm-vpn-mac_hjv6iq.png" alt="Mac VPN Configuration" width="800" height="699"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Groups
&lt;/h3&gt;

&lt;p&gt;Once connected, a VPN user will be on your network almost as if they're connected locally. Depending on your preference or threat tolerance you might want to lock this down. I've configured my firewall to block all LAN activity except for specific rules I've created, such as connecting to &lt;a href="https://pi-hole.net/"&gt;PiHole&lt;/a&gt; for DNS based ad blocking, or Plex as mentioned at the beginning.&lt;/p&gt;

&lt;p&gt;First, we want to setup a group for the VPN. We can then use this group when creating firewall rules rather than adding each possible IP. To do this, go to Profiles in the Settings sidebar and scroll down to "Port and IP Groups" - &lt;code&gt;https://[your_gateway_ip]/network/default/settings/profiles&lt;/code&gt;. Click "Create New Group".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ENdz5Due--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_800/v1668451631/udm-vpn-group_isfqbp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ENdz5Due--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_800/v1668451631/udm-vpn-group_isfqbp.png" alt="Create VPN Group settings" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll create a group called "VPN Users", with the "IPv4 Address/Subnet" type. For the address we want to enter the subnet used by the VPN server in the last section. You might notice I've used &lt;code&gt;24&lt;/code&gt; instead of the &lt;code&gt;29&lt;/code&gt; that I configured for the VPN Server. This is incase I resize my VPN network later, I still want this group to apply to all IPs on the VPN subnet.&lt;/p&gt;

&lt;p&gt;I also have another group named "RFC1918". This is a standard which defines the subnets used in private networks, you can read more about it &lt;a href="https://en.wikipedia.org/wiki/Private_network"&gt;here&lt;/a&gt;. I use this group to make blanket rules, like blocking all access to something. I then followup with another rule higher in the hierarchy that allows access for specific networks, IPs or groups. I'd recommend making this group too.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JnWFkjuN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_800/v1668452467/udm-vpn-rfc1928-group_zzjvne.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JnWFkjuN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_800/v1668452467/udm-vpn-rfc1928-group_zzjvne.png" alt="Create RFC1918 Group settings" width="800" height="616"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should now have 2 groups ready to use in the firewall.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oI5EWEEX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_800/v1668452613/udm-vpn-groups_mz68g1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oI5EWEEX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_800/v1668452613/udm-vpn-groups_mz68g1.png" alt="Group settings" width="800" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Firewall Rules
&lt;/h3&gt;

&lt;p&gt;Navigate to the Firewall &amp;amp; Security page from the Settings sidebar and scroll down to Firewall Rules - &lt;code&gt;https://[your_gateway_ip]/network/default/settings/security&lt;/code&gt;. Click "Create New Rule".&lt;/p&gt;

&lt;p&gt;First we're going to create a rule to block the VPN group from connecting to any IP on the network. We'll then follow up with additional rules allowing access to specific IPs, groups or networks (VLANs).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kcULhLxp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_800/v1668455128/udm-vpn-block-vpn-lan_o3zwl9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kcULhLxp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_800/v1668455128/udm-vpn-block-vpn-lan_o3zwl9.png" alt="Create Block VPN from LAN rule" width="800" height="1281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fields of note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Type - Set to LAN out - I'll be honest, I still don't fully understand this, but it's to do with the flow of traffic.&lt;/li&gt;
&lt;li&gt;Action - We want to drop all connections.&lt;/li&gt;
&lt;li&gt;Source Type - Where the traffic's coming from, our VPN Users group.&lt;/li&gt;
&lt;li&gt;Destination Type - Where the traffic's going, anywhere on the LAN.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note this doesn't block connections from the VPN user to the gateway, even if you use port groups. At the time of writing this it's a well documented issue with Unifi which is yet to be resolved.&lt;/p&gt;

&lt;p&gt;Now we've blocked all traffic from the VPN subnet to our LAN, we want to create some rules allowing specific connections. I'm going to create one allowing access to PiHole, but the steps are similar for allowing access to another group or network.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lh7i_UvW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_800/v1668456767/udm-vpn-allow-pihole_b6imon.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lh7i_UvW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_800/v1668456767/udm-vpn-allow-pihole_b6imon.png" alt="Create Allow VPN access to PiHole rule" width="800" height="1136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This time the Action is &lt;code&gt;Accept&lt;/code&gt; and the Destination Type is &lt;code&gt;IP Address&lt;/code&gt;, but the source is the same - the VPN Users group.&lt;/p&gt;

&lt;p&gt;Now that's added, we need to change the order of the rules as by default new rules are added to the bottom of each type, meaning anything above them such as the Block VPN from LAN rule will take precedence. On the left of each row you can click and drag, you want Allows above the Blocks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cqk5V5Jh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_800/v1668457163/udm-vpn-firewall-order_copoq5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cqk5V5Jh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/jam3sn/image/upload/c_scale%2Cw_800/v1668457163/udm-vpn-firewall-order_copoq5.png" alt="Order of firewall rules" width="800" height="113"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go ahead and add any other rules you want to allow and that's it. Connect your phone or computer, test you can connect to the allowed IPs, and also test that you can't connect to the IPs you shouldn't be able to. &lt;/p&gt;

&lt;h4&gt;
  
  
  In Closing
&lt;/h4&gt;

&lt;p&gt;So that's now how I access my home network while remote. I plan on testing it properly on a small trip in the coming weeks, but so far it seems to work nicely.&lt;/p&gt;

&lt;p&gt;I also planned on making a shortcut on my iPhone to automatically connect and disconnect from the VPN whenever I'm not on my WiFi, however iOS 16 doesn't have any support for VPN settings. Additionally, automations only support connection to a specific network, not disconnecting. Hopefully this will be expanded in future iterations.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article is also available &lt;a href="https://jamesnewman.dev/blog/vpn-on-unifi/"&gt;on my blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>homelab</category>
      <category>vpn</category>
      <category>networking</category>
    </item>
    <item>
      <title>I switched from Vercel to Cloudflare Pages</title>
      <dc:creator>James Newman</dc:creator>
      <pubDate>Thu, 03 Nov 2022 19:04:35 +0000</pubDate>
      <link>https://forem.com/jam3sn/i-switched-from-vercel-to-cloudflare-pages-abp</link>
      <guid>https://forem.com/jam3sn/i-switched-from-vercel-to-cloudflare-pages-abp</guid>
      <description>&lt;p&gt;&lt;em&gt;This article is also available &lt;a href="https://jamesnewman.dev/blog/cloudflare-pages/" rel="noopener noreferrer"&gt;on my blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Cloudflare has launched its Pages product, &lt;a href="https://pages.cloudflare.com/" rel="noopener noreferrer"&gt;Cloudflare Pages&lt;/a&gt;. Aimed at JAMstack websites and applications, it joins the many hosting services that offer easy deployment for simple sites like this one! &lt;/p&gt;

&lt;p&gt;I've been using Vercel for a while, it was known as now.sh, then Zeit when I first started using it. Using the hobby tier, their free tier, it's served its purpose just fine and in all honesty I didn't have much of a reason to leave them. However, I already manage my domains through Cloudflare and use their basic but free, privacy respecting analytics, so I figured I'd give Pages ago.&lt;/p&gt;

&lt;p&gt;Set up was a breeze. If you've setup a site on a similar service, the workflow is familiar. You link the repository, point it at the branch to monitor, add build configuration and deploy. They have presets for a number of JAMstack frameworks, including the one I use for this site, &lt;a href="https://www.11ty.dev/" rel="noopener noreferrer"&gt;11ty (Eleventy)&lt;/a&gt;. However I did need to tweak the build steps slightly to my configuration. This included the build command and output directory as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fjam3sn%2Fimage%2Fupload%2Fc_scale%2Cw_800%2Fv1667498720%2FCloudflare%2520Pages%2520build%2520settings.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fjam3sn%2Fimage%2Fupload%2Fc_scale%2Cw_800%2Fv1667498720%2FCloudflare%2520Pages%2520build%2520settings.png" alt="Cloudflare Pages build settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I use &lt;a href="https://sass-lang.com/" rel="noopener noreferrer"&gt;sass&lt;/a&gt;, or scss, to style the site, so those stylesheets should be compiled into a css file during deployment. Doing this is simply part of my &lt;code&gt;npm run build&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"styles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sass src/styles/main.scss src/assets/styles.css --style=compressed --no-source-map"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run styles &amp;amp;&amp;amp; eleventy"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also needed to adjust my rewrite rule for 404s so any urls not found are redirected to the 404 page. In Vercel, you can achieve this like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rewrites"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/(.*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"destination"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/404/index.html"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I struggled to find a straight forward way to do this with Cloudflare Pages, but after digging around a little, I found &lt;a href="https://developers.cloudflare.com/pages/platform/serving-pages/#not-found-behavior" rel="noopener noreferrer"&gt;Cloudflare can resolve 404s&lt;/a&gt; automatically to a &lt;code&gt;404.html&lt;/code&gt; file in the top level of your site, meaning I didn't need a &lt;code&gt;_redirects&lt;/code&gt; file to handle this. So in my &lt;code&gt;404.ndk&lt;/code&gt; file I simply updated the &lt;a href="https://www.11ty.dev/docs/data-frontmatter/" rel="noopener noreferrer"&gt;front matter&lt;/a&gt; to include the &lt;code&gt;permlink&lt;/code&gt;. This placed it in the top level, instead of &lt;code&gt;404/index.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;---
title: "404"
layout: base
templateId: not-found
permalink: 404.html
---
&lt;span class="nt"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;404&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hmm, we couldn't find what you were looking for...&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Home"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Back to Home&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that was it! My nameservers for jamesnewman.dev were already pointing at Cloudflare, so the DNS just needed updating which Cloudflare can also do at the click of a button. It really is straight forward.&lt;/p&gt;

&lt;h3&gt;
  
  
  My thoughts so far
&lt;/h3&gt;

&lt;p&gt;As of writing this, the sites only been on Pages for a few days. However Cloudflare analytics seem to be working better and more importantly, the site seems to load faster! Better yet, it's backed by the power, scale and security of Cloudflare.&lt;/p&gt;

&lt;p&gt;So should you switch? Maybe. Like I said at the beginning, I didn't &lt;em&gt;really&lt;/em&gt; need to switch and you probably don't need to either. But with that in mind, take a look at the feature list on &lt;a href="https://pages.cloudflare.com/" rel="noopener noreferrer"&gt;their site&lt;/a&gt;, &lt;a href="https://pages.cloudflare.com/#pricing" rel="noopener noreferrer"&gt;the pricing tiers&lt;/a&gt; and evaluate if it's worth it for you.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article is also available &lt;a href="https://jamesnewman.dev/blog/cloudflare-pages/" rel="noopener noreferrer"&gt;on my blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>hosting</category>
      <category>cloudflare</category>
      <category>blog</category>
    </item>
    <item>
      <title>Routing to multiple Minecraft servers on a host with Docker</title>
      <dc:creator>James Newman</dc:creator>
      <pubDate>Tue, 25 Oct 2022 07:58:57 +0000</pubDate>
      <link>https://forem.com/jam3sn/routing-to-multiple-minecraft-servers-on-a-host-307h</link>
      <guid>https://forem.com/jam3sn/routing-to-multiple-minecraft-servers-on-a-host-307h</guid>
      <description>&lt;p&gt;&lt;em&gt;This article is also available &lt;a href="https://jamesnewman.dev/blog/routing-minecraft-servers/"&gt;on my blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In my &lt;a href="https://dev.to/jam3sn/running-minecraft-servers-from-docker-10le"&gt;previous post&lt;/a&gt; I walked through the setup of a Minecraft server with docker. But now you might want to setup a few servers on the same host and route domains to them without different ports, a bit like reverse proxying.&lt;/p&gt;

&lt;p&gt;By default Minecraft runs on port &lt;code&gt;25565&lt;/code&gt;, but when we have multiple servers running on the same host, they can't all expose port &lt;code&gt;25565&lt;/code&gt; and so you end up with something like &lt;code&gt;25565, 25566, 25567&lt;/code&gt; etc. With &lt;a href="https://hub.docker.com/r/itzg/mc-router"&gt;mc-router&lt;/a&gt;, we can route all those domains to &lt;code&gt;25565&lt;/code&gt; and resolve them to the configured server!&lt;/p&gt;

&lt;h3&gt;
  
  
  The Environment
&lt;/h3&gt;

&lt;p&gt;At a minimum you'll need Docker installed on the host, but we'll also be using Docker Compose. If you followed the &lt;a href="https://dev.to/jam3sn/running-minecraft-servers-from-docker-10le"&gt;previous post&lt;/a&gt; you're all set. If you need to install Docker Compose, you can follow their guide &lt;a href="https://docs.docker.com/compose/install/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This solution also requires at least one domain to route to our server. Point your desired domains or subdomains at the server ip hosting your servers. If you're experimenting with this locally, you can add an entry to your hosts file to point to &lt;code&gt;localhost&lt;/code&gt;. In this post I'll be using the following example domains set in my hosts file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano /etc/hosts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mc.example.com
modded.example.com
events.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting up the router
&lt;/h3&gt;

&lt;p&gt;We'll be using another docker image from &lt;a href="https://github.com/itzg"&gt;itzg&lt;/a&gt;, this time &lt;a href="https://hub.docker.com/r/itzg/mc-router"&gt;itzg/mc-router&lt;/a&gt;. So go a head an open you docker compose file. If you followed the previous post, we'll continue using the same &lt;code&gt;docker-compose.yaml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;First we're going to need to remove our &lt;code&gt;ports&lt;/code&gt; definition for each server, we don't need to expose these any more as we'll make use of dockers internal networking. Then we can go ahead and add our &lt;code&gt;mc-router&lt;/code&gt; service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;vanilla&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vanilla&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;itzg/minecraft-server&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;EULA&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TRUE"&lt;/span&gt;
            &lt;span class="na"&gt;MEMORY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2G&lt;/span&gt;
        &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./vanilla:/data&lt;/span&gt;
        &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
        &lt;span class="na"&gt;tty&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;stdin_open&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

    &lt;span class="na"&gt;mc-router&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;itzg/mc-router&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;API_BINDING&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:25564"&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;25565:25565&lt;/span&gt;
            &lt;span class="c1"&gt;# bind the API port to only loopback, this avoids external exposure&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;127.0.0.1:25564:25564&lt;/span&gt;
        &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;--mapping=mc.example.com=vanilla:25565,modded.example.com=modded:25565,events.example.com=events:25565&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see in the &lt;code&gt;command&lt;/code&gt; line, we've mapped our domains to our containers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mc.example.com      -&amp;gt; vanilla
modded.example.com  -&amp;gt; modded
events.example.com  -&amp;gt; events
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now go ahead and startup the stack with &lt;code&gt;docker compose up&lt;/code&gt; and test them out in your Minecraft client!&lt;/p&gt;

&lt;p&gt;If you'd like to know a little more about how it works, I'd recommend taking a look at the &lt;a href="https://hub.docker.com/r/itzg/mc-router"&gt;itzg/mc-router doc&lt;/a&gt; where they include some diagrams and alternative configurations.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article is also available &lt;a href="https://jamesnewman.dev/blog/routing-minecraft-servers/"&gt;on my blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>minecraft</category>
      <category>guide</category>
    </item>
    <item>
      <title>Running Minecraft servers from Docker</title>
      <dc:creator>James Newman</dc:creator>
      <pubDate>Mon, 17 Oct 2022 07:50:33 +0000</pubDate>
      <link>https://forem.com/jam3sn/running-minecraft-servers-from-docker-10le</link>
      <guid>https://forem.com/jam3sn/running-minecraft-servers-from-docker-10le</guid>
      <description>&lt;p&gt;&lt;em&gt;This article is also available &lt;a href="https://jamesnewman.dev/blog/docker-minecraft-servers/"&gt;on my blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Since picking up docker last year it's completely changed how I set up projects, home network applications, and now how I deploy Minecraft servers for friends. Gone are the days of figuring out which version of JDK I need on an ubuntu box and remembering the commands to reconnect to a &lt;a href="https://help.ubuntu.com/community/Screen"&gt;screen&lt;/a&gt; session.&lt;/p&gt;

&lt;p&gt;In this post I'll walk you through setting up a few different Minecraft servers, running vanilla, Paper and Forge, all on the same host. In a &lt;a href="https://dev.to/blog/routing-minecraft-servers"&gt;follow up post&lt;/a&gt; I go through routing to these server on the same port.&lt;/p&gt;

&lt;p&gt;Before we get started, I'd recommend having some basic command line and linux knowledge. In addition, pre-existing docker and docker-compose experience is a bonus but &lt;strong&gt;not&lt;/strong&gt; required.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Environment
&lt;/h3&gt;

&lt;p&gt;Docker being docker, you can run this on Windows, Linux, macOS - A spare computer, the cheapest DigitalOcean droplet, heck even a Raspberry Pi! Just make sure your systems up to date, has docker and docker-compose installed. Here's what we'll be using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A docker host, the steps below are for Ubuntu but you can use any.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://hub.docker.com/r/itzg/minecraft-server"&gt;itzg/minecraft-server&lt;/a&gt; docker image to run the server.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Install Docker &amp;amp; Docker Compose
&lt;/h4&gt;

&lt;p&gt;Go ahead and follow the &lt;a href="https://docs.docker.com/engine/install/"&gt;Docker install steps&lt;/a&gt; for the platform you wish to run the server on. Here's the &lt;a href="https://docs.docker.com/engine/install/ubuntu/"&gt;Ubuntu guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Handy tip: if you're on linux, make sure you add your user to the docker group:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; docker &lt;span class="nv"&gt;$USER&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;You'll need to log out and back in again after.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now you should be all set! To double check, run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check the Docker version&lt;/span&gt;
docker &lt;span class="nt"&gt;-v&lt;/span&gt;

&lt;span class="c"&gt;# Check Docker Compose version&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating our first server with Docker Compose
&lt;/h3&gt;

&lt;p&gt;It's vary rarely I'll run a docker image with the docker command line, remembering the command and all the arguments I need is a faff. So lets define our first Minecraft server, a simple vanilla server, in a docker compose YAML file.&lt;/p&gt;

&lt;p&gt;First up, we'll create a directory to contain all our files including the Minecraft servers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create directory&lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;minecraft-servers

&lt;span class="c"&gt;# cd into the directory&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;minecraft-servers

&lt;span class="c"&gt;# Create a docker-compose.yaml file&lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;docker-compose.yaml

&lt;span class="c"&gt;# Create a directory to store our vanilla server files in&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; vanilla/server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go ahead and open the &lt;code&gt;docker-compose.yaml&lt;/code&gt;. You can use nano, vim or even connect &lt;a href="https://code.visualstudio.com/docs/remote/ssh"&gt;VS Code with SSH&lt;/a&gt;.&lt;br&gt;
In here we want to define our vanilla service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;vanilla&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vanilla&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;itzg/minecraft-server&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;25565:25565&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;EULA&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TRUE"&lt;/span&gt;
            &lt;span class="na"&gt;MEMORY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2G&lt;/span&gt;
        &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./vanilla/server:/data&lt;/span&gt;
        &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
        &lt;span class="na"&gt;tty&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;stdin_open&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the bare minimum configuration, but there's a whole bunch of options you can define such as ops, whitelist, difficulty etc, all documented &lt;a href="https://github.com/itzg/docker-minecraft-server/blob/master/README.md#server-configuration"&gt;here&lt;/a&gt;. Now we're ready to test our first server works, so lets spin it up!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start the service&lt;/span&gt;
docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll should now see the server begin to start up. It'll take a little while on the first launch as it downloads the image and generates server files. You'll know it's ready when you see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vanilla | [17:22:18] [Server thread/INFO]: Done (13.045s)! For help, type "help"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations, you can now connect to your new server using the server IP or &lt;code&gt;localhost&lt;/code&gt; if you're running it on the same machine! To exit, you can use &lt;code&gt;ctrl + c&lt;/code&gt; in the terminal.&lt;/p&gt;

&lt;p&gt;If you take a look in the &lt;code&gt;vanilla/server&lt;/code&gt; directory we created earlier, you'll see it's generated all the server files needed. You &lt;em&gt;can&lt;/em&gt; edit the &lt;code&gt;server.properties&lt;/code&gt; to make changes to the servers configuration, however I'd recommend adding these to the &lt;code&gt;environment&lt;/code&gt; block in our &lt;code&gt;docker-compose.yaml&lt;/code&gt; and simply deleting the &lt;code&gt;server.properties&lt;/code&gt; file. This file will be recreated when you next start the server with your newly added environment options.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding different server types
&lt;/h3&gt;

&lt;p&gt;So we have our vanilla server set up, but if we want to use some plugins to manage permissions or add prefixes to usernames in chat, we'll need to use a different server type. For a vanilla server that you can connect an unmodded client to, you have a few options: Bukkit, Spigot and Paper. We'll use Paper for the sake of this post.&lt;/p&gt;

&lt;p&gt;First, lets create a directory to keep our plugins in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;vanilla/plugins

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can go ahead and add any plugins to this directory and we'll configure the container to mount these. You can also leave it blank for now and once we start the server you'll see &lt;code&gt;bStats&lt;/code&gt; automatically added by Paper.&lt;/p&gt;

&lt;p&gt;Now in our &lt;code&gt;docker-compose.yaml&lt;/code&gt; file, we'll add a new entry to the &lt;code&gt;environment&lt;/code&gt; block of our &lt;code&gt;vanilla&lt;/code&gt; service, defining the server type. We'll also mount the plugins directory we just created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;vanilla&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vanilla&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;itzg/minecraft-server&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;25565:25565&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Add our server type&lt;/span&gt;
            &lt;span class="na"&gt;TYPE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PAPER&lt;/span&gt;
            &lt;span class="na"&gt;EULA&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TRUE"&lt;/span&gt;
            &lt;span class="na"&gt;MEMORY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2G&lt;/span&gt;
        &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./vanilla:/data&lt;/span&gt;
            &lt;span class="c1"&gt;# Mount our plugins directory&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./vanilla/plugins:/plugins&lt;/span&gt;
        &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
        &lt;span class="na"&gt;tty&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;stdin_open&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lets spin up the updated server, you'll see it download the new jar and create some new files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start the service&lt;/span&gt;
docker-compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you should be able to edit the configuration files for the plugins you added, log in and see them working!&lt;/p&gt;

&lt;h3&gt;
  
  
  Proxying and Routing domains to Minecraft Servers
&lt;/h3&gt;

&lt;p&gt;In a follow up post, I go through adding adding &lt;a href="https://hub.docker.com/r/itzg/mc-router"&gt;itzg/mc-router&lt;/a&gt; to route domains to multiple servers, all using the default &lt;code&gt;25565&lt;/code&gt; port. No more ugly server addresses with different ports! You can read about that &lt;a href="https://jamesnewman.dev/blog/routing-minecraft-servers"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Closing thoughts
&lt;/h3&gt;

&lt;p&gt;So in this post we've created a Vanilla server, maintained and managed through docker. I highly recommend reading through the &lt;a href="https://github.com/itzg/docker-minecraft-server"&gt;docs&lt;/a&gt; for this image as there's tons of configuration available, including support for modded servers. You can add more servers to this config and use something like &lt;a href="https://github.com/SpigotMC/BungeeCord"&gt;BungieCord&lt;/a&gt; or &lt;a href="https://github.com/PaperMC/Waterfall"&gt;PaperMC Waterfall&lt;/a&gt; switch servers ingame.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article is also available &lt;a href="https://jamesnewman.dev/blog/docker-minecraft-servers/"&gt;on my blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>minecraft</category>
      <category>guide</category>
    </item>
  </channel>
</rss>
