<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/rss.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Sam&apos;s Blog</title><description>Welcome to my blog! I&apos;m a computer networking and business applications enthusiast.
  Here I share insights, tutorials, and thoughts on networking technologies, IT infrastructure,
  and how businesses can leverage software to succeed.</description><link>https://samsblog.minersonline.uk</link><item><title>Installing Free IPA in Docker</title><link>https://samsblog.minersonline.uk/posts/installing-freeipa-in-docker</link><guid isPermaLink="true">https://samsblog.minersonline.uk/posts/installing-freeipa-in-docker</guid><description>A guide to installing Free IPA in Docker and troubleshooting common errors.</description><pubDate>Fri, 15 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;The following applications need to be installed on your system:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The guide will assume some details:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hostname: &lt;code&gt;ipa.minersonline.lan&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Storage path: &lt;code&gt;/DATA/AppData/freeipa-server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Server IP: &lt;code&gt;10.0.0.97&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You may changes these assumptions based on your requirements. The Hostname will determine the domain name of the Free IPA setup, in this example &lt;code&gt;minersonline.local&lt;/code&gt;. The Storage path will determine where Free IPA will store its data.&lt;/p&gt;
&lt;p&gt;I&apos;m running these commands on an Ubuntu 22.04 system. The commands are probably the same on your system.&lt;/p&gt;
&lt;h3&gt;1. Setup hostname&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;sudo hostnamectl set-hostname ipa.minersonline.lan
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;sudo nano /etc/hosts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the line &lt;code&gt;10.0.0.97 ipa.minersonline.lan ipa&lt;/code&gt; to the top of the file but change &lt;code&gt;10.0.0.97&lt;/code&gt; to your machine&apos;s IP&lt;/p&gt;
&lt;p&gt;Press &lt;code&gt;Control + X&lt;/code&gt; then &lt;code&gt;Y&lt;/code&gt; to save the file.&lt;/p&gt;
&lt;h3&gt;2. Configure your DNS&lt;/h3&gt;
&lt;p&gt;On your router or your DNS server (like PiHole) add the &lt;code&gt;ipa.minersonline.lan&lt;/code&gt; hostname to match the IP of your machine.&lt;/p&gt;
&lt;p&gt;:::note
This step is different for different models of routers or DNS servers, please consult their documentation.
:::&lt;/p&gt;
&lt;h2&gt;Steps&lt;/h2&gt;
&lt;h3&gt;1. Choose a container&lt;/h3&gt;
&lt;p&gt;Chose a container from the [Free IPA Docker Hub](https://hub.docker.com/r/Free IPA/freeipa-server/tags). I&apos;ve chosen &lt;code&gt;fedora-rawhide&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;2. Perform the installation&lt;/h3&gt;
&lt;p&gt;The following command will run the image we built in the last step. This will run the installation process.&lt;/p&gt;
&lt;p&gt;I recommend answering &lt;code&gt;no&lt;/code&gt; to &lt;code&gt;Do you want to configure integrated DNS (BIND)?&lt;/code&gt; because the BIND dns server caused problems during my installation.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run --name freeipa-server -ti \
   --read-only \
   -h ipa.minersonline.lan -p 53:53/udp -p 53:53 -p 80:80 -p 443:443 -p 389:389 -p 636:636 -p 88:88 -p 464:464 -p 88:88/udp -p 464:464/udp -p 123:123/udp \
   --sysctl net.ipv6.conf.all.disable_ipv6=0 \
   -v /sys/fs/cgroup/freeipa.scope:/sys/fs/cgroup:ro \
   -v /DATA/AppData/freeipa-server:/data:Z \
   --tmpfs /run --tmpfs /tmp freeipa/freeipa-server:fedora-rawhide
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;If you get any errors please see the &lt;a href=&quot;#errors&quot;&gt;errors section&lt;/a&gt; for your error.
{: .prompt-tip }&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;3. Delete the existing container&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;docker stop freeipa-server
docker rm freeipa-server
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. Restart the container&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;docker run -d --name freeipa-server -ti \
   --read-only \
   -h ipa.minersonline.lan -p 53:53/udp -p 53:53 -p 80:80 -p 443:443 -p 389:389 -p 636:636 -p 88:88 -p 464:464 -p 88:88/udp -p 464:464/udp -p 123:123/udp \
   --sysctl net.ipv6.conf.all.disable_ipv6=0 \
   -v /sys/fs/cgroup/freeipa.scope:/sys/fs/cgroup:ro \
   -v /DATA/AppData/freeipa-server:/data:Z \
   --restart unless-stopped \
   --tmpfs /run --tmpfs /tmp freeipa/freeipa-server:fedora-rawhide
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:::tip
If you get any errors please see the &lt;a href=&quot;#errors&quot;&gt;errors section&lt;/a&gt; for your error.
:::&lt;/p&gt;
&lt;h2&gt;Errors&lt;/h2&gt;
&lt;h3&gt;&lt;code&gt;Failed to create /init.scope control group: Read-only file system&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;If you get the error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Failed to create /init.scope control group: Read-only file system
Failed to allocate manager object: Read-only file system
[!!!!!!] Failed to allocate manager object.
Exiting PID 1...
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;1. Delete existing containers / data&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;docker rm freeipa-server&lt;/code&gt; and &lt;code&gt;rm -rf /DATA/AppData/freeipa-server&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;2. Perform the installation again&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;docker run --name freeipa-server -ti \
   --read-only \
   -h ipa.minersonline.lan -p 53:53/udp -p 53:53 -p 80:80 -p 443:443 -p 389:389 -p 636:636 -p 88:88 -p 464:464 -p 88:88/udp -p 464:464/udp -p 123:123/udp \
   --sysctl net.ipv6.conf.all.disable_ipv6=0 \
   --cgroupns host \
   --security-opt seccomp=unconfined \
   -v /sys/fs/cgroup/freeipa.scope:/sys/fs/cgroup:rw \
   -v /DATA/AppData/freeipa-server:/data:Z \
   --privileged \
   --tmpfs /run --tmpfs /tmp freeipa/freeipa-server:fedora-rawhide --no-ntp
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3. Delete the new container&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;docker stop freeipa-server
docker rm freeipa-server
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;4. Restart the container again&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;docker run -d --name freeipa-server -ti \
   --read-only \
   -h ipa.minersonline.lan -p 53:53/udp -p 53:53 -p 80:80 -p 443:443 -p 389:389 -p 636:636 -p 88:88 -p 464:464 -p 88:88/udp -p 464:464/udp -p 123:123/udp \
   --sysctl net.ipv6.conf.all.disable_ipv6=0 \
   --cgroupns host \
   --security-opt seccomp=unconfined \
   -v /sys/fs/cgroup/freeipa.scope:/sys/fs/cgroup:rw \
   -v /DATA/AppData/freeipa-server:/data:Z \
   --restart unless-stopped \
   --privileged \
   --tmpfs /run --tmpfs /tmp freeipa/freeipa-server:fedora-rawhide --no-ntp
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>Samuel Hulme</author></item><item><title>Configuring Next Cloud to Use Free IPA</title><link>https://samsblog.minersonline.uk/posts/configuring-nextcloud-to-use-freeipa</link><guid isPermaLink="true">https://samsblog.minersonline.uk/posts/configuring-nextcloud-to-use-freeipa</guid><description>A guide on how to configure Next Cloud to use Free IPA for authentication.</description><pubDate>Sat, 16 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;The following applications need to be installed on your system&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Next Cloud&lt;/li&gt;
&lt;li&gt;Free IPA.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The guide will assume some details:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Free IPA server hostname: &lt;code&gt;ipa.minersonline.lan&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Free IPA realm domain: &lt;code&gt;mineronline.lan&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You may changes these assumptions based on your requirements.&lt;/p&gt;
&lt;h2&gt;Steps&lt;/h2&gt;
&lt;h3&gt;1. Step up a System User Account&lt;/h3&gt;
&lt;p&gt;The System User Account is a dedicated account that the Next Cloud instance will use to get user information from your Free IPA server.&lt;/p&gt;
&lt;h4&gt;1. Login into the Free IPA web interface&lt;/h4&gt;
&lt;p&gt;Open up your browser and navigate to &lt;code&gt;https://ipa.minersonline.lan&lt;/code&gt;. Accept the security warning.&lt;/p&gt;
&lt;p&gt;If not logged in, enter your admin account details. By default, the user name is &lt;code&gt;admin&lt;/code&gt; and the password is the one you gave during the Free IPA installation.&lt;/p&gt;
&lt;h4&gt;2. Add the user&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;On the &quot;Users&quot; page click the &quot;Add&quot; button.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the &quot;User login&quot; to something explanatory, for example: &lt;code&gt;NextCloudsystemuser&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &quot;First Name&quot; and &quot;Last Name&quot; can be set to whatever you want, for example &lt;code&gt;Next Cloud&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the password to something secure and note it down.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;3. Make the user an &quot;admin&quot;&lt;/h4&gt;
&lt;p&gt;The new user needs to be an admin so it can be used to receive information about all users.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Click on the &lt;code&gt;NextCloudsystemuser&lt;/code&gt; user on the &quot;Active Users&quot; page.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open the &quot;User Groups&quot; tab.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click on the &quot;Add&quot; button.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the checkbox next to &quot;admins&quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the middle of the dialog press the button pointing to the right &quot;&amp;gt;&quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, press &quot;Add&quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2. Configure Next Cloud LDAP / AD Integration&lt;/h3&gt;
&lt;h4&gt;1. Enable / Install the &quot;LDAP user and group backend&quot; app&lt;/h4&gt;
&lt;p&gt;The &quot;LDAP user and group backend&quot; app is used to provide LDAP support for Next Cloud.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to the Next Cloud apps page and enable the &quot;LDAP user and group backend&quot; app. Optionally, I recommend installing the &quot;Write support for LDAP&quot; and the &quot;LDAP Contacts Backend&quot; app.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;2. Configure LDAP / AD connection settings&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open the &quot;Administration Settings&quot; page and go to the &quot;LDAP / AD integration&quot; page.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &quot;Host&quot; field enter your Free IPA server&apos;s hostname, for example: &lt;code&gt;ipa.minersonline.lan&lt;/code&gt;. If your running your Next Cloud in Docker then you may need to use the server&apos;s IP address instead.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the &quot;Port&quot; field to &lt;code&gt;389&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the &quot;User DN&quot; to &lt;code&gt;uid=NextCloudsystemuser,cn=users,cn=accounts,dc=minersonline,dc=lan&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;NextCloudsystemuser&lt;/code&gt; part is the &quot;User Login&quot; we set earlier.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;dc=minersonline,dc=lan&lt;/code&gt; part depends on your Free IPA realm domain. For example if your domain is &lt;code&gt;office.example.com&lt;/code&gt; then you would use &lt;code&gt;dc=office,dc=example,dc=com&lt;/code&gt;.
{: .prompt-tip }&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the &quot;Password&quot; to what you noted down earlier.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then press &quot;Save Credentials&quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the &quot;One Base DN per line&quot; to &lt;code&gt;dc=minersonline,dc=lan&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Again, The &lt;code&gt;dc=minersonline,dc=lan&lt;/code&gt; part depends on your Free IPA realm domain. For example if your domain is &lt;code&gt;office.example.com&lt;/code&gt; then you would use &lt;code&gt;dc=office,dc=example,dc=com&lt;/code&gt;.
{: .prompt-tip }&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, press &quot;Continue&quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;3. Configure LDAP Groups&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;On the same page click on the &quot;Groups&quot; tab.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the &quot;Edit LDAP Query&quot; link.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &quot;Edit LDAP Query&quot; text box type: &lt;code&gt;(|(cn=ipausers))&lt;/code&gt;. This filter will add the &lt;code&gt;ipausers&lt;/code&gt; group from the Identity &amp;gt; Groups page on the Free IPA interface.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;4. Configure LDAP Login Attributes&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;On the same page click on the &quot;Login Attributes&quot; tab.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the &quot;Edit LDAP Query&quot; link.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &quot;Edit LDAP Query&quot; text box type: &lt;code&gt;(&amp;amp;(objectclass=*)(uid=%uid))&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, press &quot;Continue&quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;5. Configure Advanced Settings&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;On the same page click on the &quot;Advanced&quot; tab.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open up the &quot;Directory Settings&quot; section.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Inside the &quot;Base User Tree&quot; type &lt;code&gt;cn=users,cn=accounts,dc=minersonline,dc=lan&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Again, The &lt;code&gt;dc=minersonline,dc=lan&lt;/code&gt; part depends on your Free IPA realm domain. For example if your domain is &lt;code&gt;office.example.com&lt;/code&gt; then you would use &lt;code&gt;dc=office,dc=example,dc=com&lt;/code&gt;.
{: .prompt-tip }&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Inside the &quot;Base Group Tree&quot; type &lt;code&gt;cn=groups,cn=accounts,dc=minersonline,dc=lan&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Again, The &lt;code&gt;dc=minersonline,dc=lan&lt;/code&gt; part depends on your Free IPA realm domain. For example if your domain is &lt;code&gt;office.example.com&lt;/code&gt; then you would use &lt;code&gt;dc=office,dc=example,dc=com&lt;/code&gt;.
{: .prompt-tip }&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the &quot;Group-Member association&quot; to &lt;code&gt;member&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open up the &quot;Special Attributes&quot; section.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Make sure the &quot;Email Field&quot; is set to &lt;code&gt;mail&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the &quot;User Home Folder Naming Rule&quot; to &lt;code&gt;cn&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally press &quot;Test Configuration&quot;. If all settings are good then a &quot;Valid configuration, connection established!&quot; message should be displayed.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><author>Samuel Hulme</author></item><item><title>Configuring Next Cloud to Use Samba</title><link>https://samsblog.minersonline.uk/posts/configuring-nextcloud-to-use-samaba</link><guid isPermaLink="true">https://samsblog.minersonline.uk/posts/configuring-nextcloud-to-use-samaba</guid><description>A guide on how to configure Next Cloud to use Samba for authentication.</description><pubDate>Thu, 21 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;The following applications need to be installed on your system&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Next Cloud&lt;/li&gt;
&lt;li&gt;A Samba domain controller.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The guide will assume some details:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hostname: &lt;code&gt;ipa.minersonline.lan&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Storage path: &lt;code&gt;/DATA/AppData/freeipa-server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Server IP: &lt;code&gt;10.0.0.97&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You may changes these assumptions based on your requirements.&lt;/p&gt;
&lt;h2&gt;Steps&lt;/h2&gt;
&lt;h3&gt;1. Step up a System User Account&lt;/h3&gt;
&lt;p&gt;The System User Account is a dedicated account that the Next Cloud instance will use to get user information from your Sa,ba server. Call the user &lt;code&gt;NextCloudsystemuser&lt;/code&gt;, and set a secure password and note it down.&lt;/p&gt;
&lt;p&gt;If you have Windows clients connected to the domain then you can use the &quot;Active Directory Users and Computers&quot; program to add the user.&lt;/p&gt;
&lt;p&gt;If not, you may need use the Samba command line tools.&lt;/p&gt;
&lt;h3&gt;2. Allow Next Cloud to accept any LDAP certificate&lt;/h3&gt;
&lt;h4&gt;1. Connect to your Next Cloud server&apos;s console&lt;/h4&gt;
&lt;p&gt;This depends on how you have installed Next Cloud.
For me:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo docker exec -it nextcloud bash
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;2. Edit LDAP configuration&lt;/h4&gt;
&lt;p&gt;Open the file &lt;code&gt;/etc/ldap/ldap.conf&lt;/code&gt; and add the line to the bottom:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TLS_REQCERT never
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3. Restart Next Cloud&lt;/h4&gt;
&lt;p&gt;You may need to restart your Next Cloud server.
For me:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo docker restart nextcloud
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. Configure Next Cloud LDAP / AD Integration&lt;/h3&gt;
&lt;h4&gt;1. Enable / Install the &quot;LDAP user and group backend&quot; app&lt;/h4&gt;
&lt;p&gt;The &quot;LDAP user and group backend&quot; app is used to provide LDAP support for Next Cloud.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to the Next Cloud apps page and enable the &quot;LDAP user and group backend&quot; app. Optionally, I recommend installing the &quot;Write support for LDAP&quot; and the &quot; LDAP Contacts Backend&quot; app.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;2. Configure LDAP / AD connection settings&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open the &quot;Administration Settings&quot; page and go to the &quot;LDAP / AD integration&quot; page.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &quot;Host&quot; field enter your Samba server&apos;s hostname, for example: &lt;code&gt;ldaps://ipa.minersonline.lan&lt;/code&gt;. If your running your Next Cloud in Docker then you may need to use the server&apos;s IP address instead.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the &quot;Port&quot; field to &lt;code&gt;636&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the &quot;User DN&quot; to &lt;code&gt;cn=NextCloudsystemuser,cn=users,dc=minersonline,dc=lan&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;NextCloudsystemuser&lt;/code&gt; part is the user account we set earlier.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;dc=minersonline,dc=lan&lt;/code&gt; part depends on your Samba realm domain. For example if your domain is &lt;code&gt;office.example.com&lt;/code&gt; then you would use &lt;code&gt;dc=office,dc=example,dc=com&lt;/code&gt;.
{: .prompt-tip }&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the &quot;Password&quot; to what you noted down earlier.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then press &quot;Save Credentials&quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the &quot;One Base DN per line&quot; to &lt;code&gt;dc=minersonline,dc=lan&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Again, The &lt;code&gt;dc=minersonline,dc=lan&lt;/code&gt; part depends on your Samba realm domain. For example if your domain is &lt;code&gt;office.example.com&lt;/code&gt; then you would use &lt;code&gt;dc=office,dc=example,dc=com&lt;/code&gt;.
{: .prompt-tip }&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, press &quot;Continue&quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;3. Configure LDAP Groups&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;On the same page click on the &quot;Groups&quot; tab.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the &quot;Edit LDAP Query&quot; link.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &quot;Edit LDAP Query&quot; text box type: &lt;code&gt;(&amp;amp;(objectclass=group))&lt;/code&gt;. This filter will add all Samba groups (even the default builtin ones).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;4. Configure LDAP Login Attributes&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;On the same page click on the &quot;Login Attributes&quot; tab.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the &quot;Edit LDAP Query&quot; link.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &quot;Edit LDAP Query&quot; text box type: &lt;code&gt;(&amp;amp;(objectclass=person))&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, press &quot;Continue&quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;5. Configure Advanced Settings&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;On the same page click on the &quot;Advanced&quot; tab.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open up the &quot;Directory Settings&quot; section.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Inside the &quot;User Display Name&quot; type &lt;code&gt;displayName&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Inside the &quot;Base User Tree&quot; type &lt;code&gt;cn=users,dc=minersonline,dc=lan&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Again, The &lt;code&gt;dc=minersonline,dc=lan&lt;/code&gt; part depends on your Samba realm domain. For example if your domain is &lt;code&gt;office.example.com&lt;/code&gt; then you would use &lt;code&gt;dc=office,dc=example,dc=com&lt;/code&gt;.
{: .prompt-tip }&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Inside the &quot;Base Group Tree&quot; type &lt;code&gt;cn=users,dc=minersonline,dc=lan&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Again, The &lt;code&gt;dc=minersonline,dc=lan&lt;/code&gt; part depends on your Samba realm domain. For example if your domain is &lt;code&gt;office.example.com&lt;/code&gt; then you would use &lt;code&gt;dc=office,dc=example,dc=com&lt;/code&gt;.
{: .prompt-tip }&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the &quot;Group-Member association&quot; to &lt;code&gt;member (AD)&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open up the &quot;Special Attributes&quot; section.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set the &quot;User Home Folder Naming Rule&quot; to &lt;code&gt;cn&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally press &quot;Test Configuration&quot;. If all settings are good then a &quot;Valid configuration, connection established!&quot; message should be displayed.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><author>Samuel Hulme</author></item><item><title>Installing Samba on Ubuntu</title><link>https://samsblog.minersonline.uk/posts/installing-samba-on-ubuntu</link><guid isPermaLink="true">https://samsblog.minersonline.uk/posts/installing-samba-on-ubuntu</guid><description>A guide on how to install and configure Samba as an Active Directory Domain Controller on Ubuntu.</description><pubDate>Thu, 21 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;This guide recommends using Ubuntu 22.04 or later.&lt;/p&gt;
&lt;p&gt;The guide will assume some details:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Server IP: &lt;code&gt;10.0.0.97&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Kerberos Realm: &lt;code&gt;MINERSONLINE.LAN&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Kerberos server hostname: &lt;code&gt;ipa.minersonline.lan&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Kerberos administrative server hostname: &lt;code&gt;ipa.minersonline.lan&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You may changes these assumptions based on your requirements.&lt;/p&gt;
&lt;h3&gt;1. Setup hostname&lt;/h3&gt;
&lt;p&gt;Set the hostname.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo hostnamectl set-hostname ipa.minersonline.lan
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the hostname to hosts file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo nano /etc/hosts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the line &lt;code&gt;10.0.0.97 ipa.minersonline.lan ipa&lt;/code&gt; to the top of the file but change &lt;code&gt;10.0.0.97&lt;/code&gt; to your machine&apos;s IP&lt;/p&gt;
&lt;p&gt;Press &lt;code&gt;Control + X&lt;/code&gt; then &lt;code&gt;Y&lt;/code&gt; to save the file.&lt;/p&gt;
&lt;h3&gt;2. Install dependencies&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install samba krb5-user krb5-config winbind libpam-winbind libnss-winbind
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;During installation you may get asked for your Kerberos Realm, Kerberos server hostname, and Kerberos administrative server hostname.&lt;/p&gt;
&lt;h3&gt;3. Provision Samba&lt;/h3&gt;
&lt;h4&gt;1. Stop existing Samba services&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl stop samba-ad-dc.service smbd.service nmbd.service winbind.service
sudo systemctl disable samba-ad-dc.service smbd.service nmbd.service winbind.service
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;2. Backup Samba configuration&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo mv /etc/samba/smb.conf /etc/samba/smb.conf.initial
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3. Reconfigure Samba&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo samba-tool domain provision --use-rfc2307 --interactive
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will get asked for the following information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Realm: &lt;code&gt;MINERSONLINE.LAN&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Domain: &lt;code&gt;MINERSONLINE&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Server Role: &lt;code&gt;dc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;DNS backend: &lt;code&gt;SAMBA_INTERNAL&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;DNS forwarder IP address: Your DNS server&apos;s IP (normally your gateway) or Cloudflare (1.1.1.1) or Google (8.8.8.8).&lt;/li&gt;
&lt;li&gt;Administrator password: Enter something secure and rememberable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;4. Make a link to use Samba&apos;s Kerberos configuration&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo mv /etc/krb5.conf /etc/krb5.conf.initial
sudo ln -s /var/lib/samba/private/krb5.conf /etc/
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;4. Start Samba&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo samba
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. Configure local DNS&lt;/h3&gt;
&lt;p&gt;DNS is used so external services can locate the domain controller and query the services located on it. This will allow clients to connect to the domain controller easily.&lt;/p&gt;
&lt;h4&gt;1. Install resolvconf&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo apt install resolvconf
sudo systemctl enable --now resolvconf.service
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;2. Configure resolvconf&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo nano /etc/resolvconf/resolv.conf.d/head
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add &lt;code&gt;nameserver 127.0.01&lt;/code&gt; at the bottom. Press &lt;code&gt;Control + X&lt;/code&gt; then &lt;code&gt;Y&lt;/code&gt; to save the file.
We use &lt;code&gt;127.0.0.1&lt;/code&gt; because Samba is acting as the DNS server and they are forwarding external DNS requests to outside world.&lt;/p&gt;
&lt;h3&gt;3. Delete conflicting DNS records&lt;/h3&gt;
&lt;p&gt;Doing the command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;samba-tool dns query 10.0.0.97 minersonline.lan minersonline.lan A
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;will allow you to check if you have conflicting DNS records. If the IPs &lt;code&gt;172.17.0.1&lt;/code&gt;, &lt;code&gt;172.19.0.1&lt;/code&gt;, and &lt;code&gt;172.18.0.1&lt;/code&gt; appear above the server&apos;s ipa &lt;code&gt;10.0.0.97&lt;/code&gt;. These conflicting records will confuse clients because they will try to connect to themselves instead of the domain controller.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;samba-tool dns delete 10.0.0.97 minersonline.lan minersonline.lan A 172.17.0.1
samba-tool dns delete 10.0.0.97 minersonline.lan minersonline.lan A 172.19.0.1
samba-tool dns delete 10.0.0.97 minersonline.lan minersonline.lan A 172.18.0.1

samba-tool dns delete 10.0.0.97 minersonline.lan ipa.minersonline.lan A 172.17.0.1
samba-tool dns delete 10.0.0.97 minersonline.lan ipa.minersonline.lan A 172.19.0.1
samba-tool dns delete 10.0.0.97 minersonline.lan ipa.minersonline.lan A 172.18.0.1
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. Running Samba on startup&lt;/h3&gt;
&lt;p&gt;Running Samba on system startup is a good idea if you want clients to be allowed to connect automatically. To do this run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo update-rc.d smbd defaults
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5. Testing / verification&lt;/h3&gt;
&lt;h4&gt;1. Verify DNS is working&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;host -t SRV _kerberos._udp.minersonline.lan
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should get a message like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;_kerberos._udp.minersonline.lan has SRV record 0 100 88 ipa.minersonline.lan.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. Test Kerberos&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;kinit administrator@MINERSONLINE.LAN
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will get asked for the password you set earlier. If successful, you may get a response like &lt;code&gt;Warning: Your password will expire in 41 days on Fri 26 Jan 2024 12:30:09 GMT&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;klist&lt;/code&gt; command will show you a list of your Kerberos tickets you made with &lt;code&gt;kinit&lt;/code&gt;.&lt;/p&gt;
</content:encoded><author>Samuel Hulme</author></item><item><title>UniFi Vpn With Active Directory and Radius</title><link>https://samsblog.minersonline.uk/posts/unifi-vpn-with-active-directory-and-radius</link><guid isPermaLink="true">https://samsblog.minersonline.uk/posts/unifi-vpn-with-active-directory-and-radius</guid><description>A guide on how to set up a UniFi VPN that uses Active Directory and RADIUS for authentication.</description><pubDate>Sat, 05 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this guide we will set up a VPN on a UniFi network that uses a RADIUS server that is backed by Active Directory for authentication.&lt;/p&gt;
&lt;h2&gt;Step 1. Set up a RADIUS server&lt;/h2&gt;
&lt;p&gt;To use RADIUS for authentication, you must have a RADIUS server configured.
The RADIUS server built into UniFi cannot be configured to use Active Directory, so an external RADIUS server is required.
Here is a list of potential RADIUS servers you can use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Microsoft Network Policy Server (NPS) &lt;a href=&quot;https://learn.microsoft.com/en-us/windows-server/networking/technologies/nps/nps-plan-server?source=recommendations&quot;&gt;Introduction guide&lt;/a&gt; (&lt;strong&gt;Windows Server only&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.freeradius.org/&quot;&gt;FreeRADIUS&lt;/a&gt; (&lt;strong&gt;Potentially Linux only? [TBC]&lt;/strong&gt;) [^1]&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;[^1]: If you are using a Windows Server, you can create a Linux virtual machine using Hyper V, or with an alternative Hypervisor.&lt;/p&gt;
&lt;h2&gt;Step 2. Create a RADIUS profile in UniFi&lt;/h2&gt;
&lt;p&gt;A RADIUS profile is required to tell UniFi where to find the RADIUS server. To create a RADIUS profile, open the Network app and navigate to &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Profiles&lt;/strong&gt; &amp;gt; &lt;strong&gt;RADIUS&lt;/strong&gt;.
At the bottom of the table, click &lt;strong&gt;Create New&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./1728127006970-144.png&quot; alt=&quot;&quot; title=&quot;Figure 1. A screenshot of the UniFi create RADIUS profile page&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Once you have done that, you will get the form as shown in Figure 1.
The options of the form that we are interested in are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Name&lt;/strong&gt;: This is the name RADIUS profile that will be displayed inside UniFi.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authentication Servers&lt;/strong&gt;: This is where you enter the IP address, Port, and Shared Secret from your RADIUS authentication servers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accounting&lt;/strong&gt;: This is a checkbox that enables the Accounting Servers fields.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Account Servers&lt;/strong&gt;: This is where you enter the IP address, Port, and Shared Secret from your RADIUS accounting servers.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In most setups, the RADIUS authentication port is 1812, the RADIUS accounting port is 1813, both IP addresses will point to the same RADIUS server, and the shared secret is what you have configured on your RADIUS server.
Once you have done that, make sure to click &lt;strong&gt;Apply Changes&lt;/strong&gt; at the bottom.&lt;/p&gt;
&lt;h2&gt;Step 3. Create a UniFi VPN&lt;/h2&gt;
&lt;p&gt;You can create a VPN on any UniFi Gateway by using a built-in VPN server. To do this, open the UniFi Network app, and navigate to &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;VPN&lt;/strong&gt; &amp;gt; &lt;strong&gt;VPN Server&lt;/strong&gt;. Once you have done this, click &lt;strong&gt;Create New&lt;/strong&gt; at the bottom of the table.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./1728130538628-166.png&quot; alt=&quot;&quot; title=&quot;Figure 2. UniFi create VPN page&quot; /&gt;&lt;/p&gt;
&lt;p&gt;When you have done that, you will get another form, as shown in Figure 2.
The options of the form that we are interested in are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;VPN Type&lt;/strong&gt;: Make sure you use &lt;strong&gt;Open VPN&lt;/strong&gt; [^2]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Name&lt;/strong&gt;: This is the name VPN profile that will be displayed inside UniFi.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advanced&lt;/strong&gt;: Switch this to &lt;strong&gt;Manual&lt;/strong&gt; to enable more options.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RADIUS Profile&lt;/strong&gt;: This is a dropdown list that contains all RADIUS profiles. Choose the profile you made in step 2.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gateway / Subnet&lt;/strong&gt;: Use this option to configure the IP range for your VPN clients.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If your UniFi Gateway is behind another NAT (e.g., another router) then make sure to enable &lt;strong&gt;Use Alternate Address for Clients&lt;/strong&gt; and then fill out the input field with the WAN IP address of that router or use a public Fully Qualified Domain Name that points to your local network.&lt;/p&gt;
&lt;p&gt;[^2]: WireGuard does not have a RADIUS option, and L2TP is not supported by several operating systems (Ubiquiti does not recommend it).&lt;/p&gt;
</content:encoded><author>Samuel Hulme</author></item><item><title>Controlling Which Vlans UniFi Teleport Can Use</title><link>https://samsblog.minersonline.uk/posts/controlling-which-vlans-unifi-teleport-can-use</link><guid isPermaLink="true">https://samsblog.minersonline.uk/posts/controlling-which-vlans-unifi-teleport-can-use</guid><description>A guide on how to restrict UniFi Teleport users to specific VLANs.</description><pubDate>Wed, 09 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::important
As of August 2025, Ubiquiti has released version 9.4.19 of the UniFi Network application, which collapses the &quot;Traffic &amp;amp; Firewall Rules&quot; and other rules into a single &quot;Policy Table&quot; interface. You need to navigate to &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt;  &lt;strong&gt;Policy Table&lt;/strong&gt; and toggle the Firewall type filter to manage your firewall rules. The process of creating rules remains similar, but the interface has been streamlined. - &lt;em&gt;September 2025&lt;/em&gt;
:::&lt;/p&gt;
&lt;p&gt;In this guide we will learn how to configure which IPs and VLANs users connected via UniFi Teleport can access.&lt;/p&gt;
&lt;h2&gt;Step 1. Identify the IP range that Teleport uses.&lt;/h2&gt;
&lt;p&gt;In order to know who we are controlling we need the know the IP range. One way to find this is to inspect a device connected with UniFi Teleport.&lt;/p&gt;
&lt;p&gt;To do this, open the Network app and navigate to &lt;strong&gt;Client Devices&lt;/strong&gt;. On this page you will find a list of all the clients and their IP address. Clients that are connected with UniFi Teleport will have the connection type of &quot;VPN&quot;. In Figure 1 you can see I have two devices one with the IP &quot;&lt;code&gt;192.168.2.3&lt;/code&gt;&quot; and &quot;&lt;code&gt;192.168.2.2&lt;/code&gt;&quot;, so, the subnet for this Teleport instance would be &quot;&lt;code&gt;192.168.2.0/24&lt;/code&gt;&quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./Screenshot_2024-10-09_171911_-_Copy.png&quot; alt=&quot;&quot; title=&quot;Figure 1. Screenshot of the client devices page showing two devices connected with UniFi Teleport.&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Step 2. Create an IP group with the Teleport subnet&lt;/h2&gt;
&lt;p&gt;Open the Network app and navigate to, &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Profiles&lt;/strong&gt; &amp;gt; &lt;strong&gt;IP Groups&lt;/strong&gt;, then at the bottom of the table click &lt;strong&gt;Create New&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Then fill out options with the following options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Profile Name: (this can be whatever you want, I&apos;ve called it &quot;Teleport Users&quot;)&lt;/li&gt;
&lt;li&gt;Type: IPv4 Address/Subnet&lt;/li&gt;
&lt;li&gt;Address: (Use the subnet we found earlier, in my case its &quot;&lt;code&gt;192.168.2.0/24&lt;/code&gt;&quot;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then, press &lt;strong&gt;Add&lt;/strong&gt; (to the right of the Address), and &lt;strong&gt;Add&lt;/strong&gt; at the bottom of the page.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./Screenshot_2024-10-09_173413.png&quot; alt=&quot;&quot; title=&quot;Figure 2. Screenshot of the IP Groups page showing the empty form to create a new IP group for Teleport users.&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Step 3. Block Teleport from all VLANs&lt;/h2&gt;
&lt;p&gt;By default we should block Teleport from accessing all VLANs, then only allow the ones we Teleport to have.&lt;/p&gt;
&lt;p&gt;To do this, open the Network app and navigate to &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Security&lt;/strong&gt; &amp;gt; &lt;strong&gt;Traffic &amp;amp; Firewall Rules&lt;/strong&gt; &amp;gt; &lt;strong&gt;Advanced&lt;/strong&gt;. Scroll to the bottom, then press &lt;strong&gt;Create Entry&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Then fill out the form just like I have in Figure 3.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./Screenshot_2024-10-09_174411.png&quot; alt=&quot;&quot; title=&quot;Figure 3. Screenshot of the firewall rule creation form showing the options to block Teleport users from accessing the LAN.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can change the name to be whatever you want, and use the same Address Group you made earlier.&lt;/p&gt;
&lt;h2&gt;Step 4. Create an allowlist for Teleport.&lt;/h2&gt;
&lt;p&gt;To create an allowlist, create another IP group like we did Step 2, but instead of having the Teleport subnet, you should have all the IPs or subnets you want Teleport to have. For an example you can look at Figure 4.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./Screenshot_2024-10-09_184602.png&quot; alt=&quot;&quot; title=&quot;Figure 4. Screenshot of the IP Groups page showing an IP group named &amp;quot;Teleport Allowlist&amp;quot; with two devices added to it.&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Step 4.2. Create a firewall rule for the allowlist.&lt;/h3&gt;
&lt;p&gt;On the same page where we made the &quot;Block Teleport users from LAN&quot; rule, we should make another rule, by using a similar process like in Step 3. Then fill out the form like seen in Figure 5.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./Screenshot_2024-10-09_185409.png&quot; alt=&quot;&quot; title=&quot;Figure 5. Screenshot of the firewall rule creation form showing the options to allow Teleport users to access only the IPs in the &amp;quot;Teleport Allowlist&amp;quot; IP group.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You may call the rule what ever you want, and you must make sure to use the Address Groups we made earlier.&lt;/p&gt;
&lt;h3&gt;Step 4.3. Move the allow rule above the block rule&lt;/h3&gt;
&lt;p&gt;All firewall rules are applied from the top to bottom, so if you have a block rule above an allow rule, then your block rule will take priority.
So we must make sure the allowlist rule is above our blocking rule.
To do this, you can grab the 6 dots icon next to the allow rule and move it above the block rule. If done successfully, it will appear like seen in Figure 6.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./Screenshot_2024-10-09_185848.png&quot; alt=&quot;&quot; title=&quot;Figure 6. Screenshot of the firewall rules list showing the &amp;quot;Allow Teleport users to access defined&amp;quot; rule above the &amp;quot;Block Teleport users from LAN&amp;quot; rule.&quot; /&gt;&lt;/p&gt;
</content:encoded><author>Samuel Hulme</author></item><item><title>Using UniFi Talk with a Kamailio SIP Trunk</title><link>https://samsblog.minersonline.uk/posts/using-unifi-talk-with-a-kamilio-sip-trunk</link><guid isPermaLink="true">https://samsblog.minersonline.uk/posts/using-unifi-talk-with-a-kamilio-sip-trunk</guid><description>A guide to setting up a Kamailio SIP trunk for use with UniFi Talk, enabling a non-PSTN environment for testing and experimentation.</description><pubDate>Sat, 21 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In recent days, I’ve been experimenting with UniFi Talk and wanted a SIP trunk that’s not part of the PSTN - something I could &lt;em&gt;play with without limitations&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;What Is a SIP Trunk?&lt;/h3&gt;
&lt;p&gt;A &lt;strong&gt;SIP trunk&lt;/strong&gt; is a connection to a SIP provider that handles inbound and outbound call routing - traditionally to and from the PSTN.&lt;/p&gt;
&lt;p&gt;To simulate that environment, we’ll need to create a local SIP provider.&lt;/p&gt;
&lt;h3&gt;What Does a SIP Provider Do?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Routes calls between multiple SIP endpoints or trunks&lt;/li&gt;
&lt;li&gt;Allocates numbers (DIDs) to subscribers&lt;/li&gt;
&lt;li&gt;Authenticates users and prevents number hijacking&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Why Kamailio?&lt;/h3&gt;
&lt;p&gt;Kamailio can handle all of these roles - it&apos;s an open-source SIP server designed for flexibility and scalability.&lt;/p&gt;
&lt;h2&gt;Setting Up Kamailio&lt;/h2&gt;
&lt;p&gt;We&apos;ll run Kamailio using Docker Compose with a minimal config.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  kamailio:
    image: ghcr.io/kamailio/kamailio:6.0.1-noble
    ports:
      - 5060:5060
      - 5060:5060/udp
    volumes:
      - ./kamailio.cfg:/etc/kamailio/kamailio.cfg
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are two important things here:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Port 5060 TCP+UDP is used for SIP traffic&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;kamailio.cfg&lt;/code&gt; file needs to be create alongside the docker compose file&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;My basic &lt;a href=&quot;https://github.com/nickvsnetworking/kamailio-101-tutorial/blob/master/Kamailio%20101%20-%20Part%206%20-%20Reusing%20Code&quot;&gt;Kamailio config&lt;/a&gt; is actually borrowed from NickVsNetworking who has a great &lt;a href=&quot;https://nickvsnetworking.com/tag/kamailio-101/&quot;&gt;tutorial series on Kamailio configuration&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Configuring UniFi Talk&lt;/h2&gt;
&lt;p&gt;Firstly we need to make sure the Static Signalling port is enabled:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to: &lt;code&gt;Talk&lt;/code&gt; &amp;gt; &lt;code&gt;Settings&lt;/code&gt; &amp;gt; &lt;code&gt;System&lt;/code&gt; &amp;gt; &lt;code&gt;General&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Then tick the box &lt;code&gt;Static Signalling Port&lt;/code&gt;, any number is fine but &lt;code&gt;6767&lt;/code&gt; is the default.&lt;/li&gt;
&lt;li&gt;Make sure to &lt;a href=&quot;https://help.ui.com/hc/en-us/articles/18020323453847-Adding-a-Third-Party-SIP-Provider-to-UniFi-Talk#4&quot;&gt;appropriately forward this port&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Finally we can now configure the SIP trunk:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to: &lt;code&gt;Talk&lt;/code&gt; &amp;gt; &lt;code&gt;Settings&lt;/code&gt; &amp;gt; &lt;code&gt;System&lt;/code&gt; &amp;gt; &lt;code&gt;Third-party SIP&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Create New&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;Provider&lt;/code&gt; to &lt;code&gt;Custom&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set the provider name to whatever you want.&lt;/li&gt;
&lt;li&gt;Add the custom fields:&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field Name&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;proxy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Kamailio IP or domain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;realm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same as proxy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;domain&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same as proxy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dtmfmode&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;rfc2833&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;password&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any placeholder (or real password if using auth)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;register&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;username&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Your E.164 phone number&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;extension&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;auto_to_user&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;from-domain&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;location&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;auth-username&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same as username&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;UniFi Talk expects E.164-format numbers for proper routing.
For isolated, non-PSTN use, I recommend numbers like &lt;code&gt;+999xxxxxxxx&lt;/code&gt; as &lt;code&gt;+999&lt;/code&gt; is reserved for testing and documentation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Add your phone number in the &lt;code&gt;Phone Numbers&lt;/code&gt; list.&lt;/li&gt;
&lt;li&gt;Add the IP addresses of your Kamailio server in to the &lt;code&gt;IP Address Range&lt;/code&gt;, if you have a single IP you can use /32 in your range.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;You now have a fully functional, non-PSTN SIP trunk integrated into UniFi Talk.
All calls will route through Kamailio just like a real SIP provider - but with no subscription, no upstream carrier, and total control.&lt;/p&gt;
&lt;p&gt;This setup lets you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Test call flows, IVRs, and voicemail&lt;/li&gt;
&lt;li&gt;Simulate users and devices&lt;/li&gt;
&lt;li&gt;Experiment with SIP signaling and Kamailio scripting&lt;/li&gt;
&lt;li&gt;Do it all without touching the real telephone network&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Samuel Hulme</author></item><item><title>How I Built `mc-router`: An Enterprise-Ready Minecraft Proxy in Under 4 Hours</title><link>https://samsblog.minersonline.uk/posts/how-i-built-mc-router-an-enterprise-ready-minecraft-proxy-in-under-4-hours</link><guid isPermaLink="true">https://samsblog.minersonline.uk/posts/how-i-built-mc-router-an-enterprise-ready-minecraft-proxy-in-under-4-hours</guid><description>A deep dive into the rapid development of `mc-router`, a high-performance Minecraft proxy built with Rust, designed for multi-tenant hosting environments.</description><pubDate>Tue, 26 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;:::note
The article has since been updated with additional calcifications via footnotes. - &lt;em&gt;September 2025&lt;/em&gt;
:::&lt;/p&gt;
&lt;p&gt;In just 3 hours and 38 minutes, I built &lt;a href=&quot;https://github.com/CloudinatorMC/mc-router&quot;&gt;&lt;code&gt;mc-router&lt;/code&gt;&lt;/a&gt; an enterprise-ready Minecraft ingress proxy designed to handle incoming connections and route them to the right backend servers. It ships with native multi-tenant support, HAProxy protocol, UDP forwarding, and even a draft cloud configuration API.&lt;/p&gt;
&lt;p&gt;I&apos;ve been trying to find a good Minecraft proxy for ingress traffic for a while now, but I&apos;ve come to the conclusion that none were designed for multi-tenancy hosting environments natively - &lt;em&gt;unless you workaround with your own custom plugins&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Why Build a New Proxy?&lt;/h2&gt;
&lt;p&gt;Existing Minecraft proxies are not designed for ingress, instead focusing on transferring of players to different servers mid-game. This limitation prompted the need for a new solution that could handle incoming connections efficiently while providing advanced features like cloud config synchronisation and TLS tunnelling.&lt;/p&gt;
&lt;p&gt;Existing solutions that I evaluated:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;BungeeCord - The original Minecraft proxy, known for its simplicity and ease of use. However, it lacks advanced features like TLS tunnelling and cloud configuration synchronisation.&lt;/li&gt;
&lt;li&gt;Gate - A modern Minecraft proxy written in Go, offering better performance than BungeeCord. Gate in Lite mode is a good option for single IP but multi-server setups, but it still lacks TLS tunnelling and cloud configuration synchronisation.&lt;/li&gt;
&lt;li&gt;Velocity - It is a popular Minecraft proxy known for its performance and scalability often utilised to allow players to switch between different worlds (each with a different backend server) mid-game. However, it lacks built-in support for TLS tunnelling and cloud configuration synchronisation.&lt;/li&gt;
&lt;li&gt;Waterfall - A fork of BungeeCord, designed to be more stable and performant. However, it still lacks advanced features like TLS tunnelling and cloud configuration synchronisation.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Introducing &lt;code&gt;mc-router&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/CloudinatorMC/mc-router&quot;&gt;&lt;code&gt;mc-router&lt;/code&gt;&lt;/a&gt; is a high-performance Minecraft proxy built with Rust, designed to handle incoming connections and route them to the appropriate backend servers.&lt;/p&gt;
&lt;p&gt;Existing implemented features:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Routing based on the &lt;a href=&quot;https://minecraft.wiki/w/Java_Edition_protocol/Packets#Handshake&quot;&gt;Handshake packet&lt;/a&gt; - Allows routing players to different backend servers based on the hostname they use to connect.&lt;/li&gt;
&lt;li&gt;HAProxy Protocol v1 support - Allows passing the original client&apos;s IP address to the backend game server, which is crucial for logging and player management.&lt;/li&gt;
&lt;li&gt;Optional UDP packet routing - Supports routing UDP packets, which is essential for a few Minecraft mods.&lt;/li&gt;
&lt;li&gt;A config service API draft - Once completed, this will allow dynamic configuration of the proxy via a RESTful API secured with ed25519 keys. [^1]&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;[^1]: This API has since become a plain JSON over WebSocket service, allowing real-time updates to the proxy configuration &lt;a href=&quot;https://github.com/CloudinatorMC/mc-router/tree/main/src/management_api&quot;&gt;see the code&lt;/a&gt; for more details.&lt;/p&gt;
&lt;p&gt;Upcoming features:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;TLS tunnelling - Enables secure connections to the backend game servers, enhancing security and privacy. [^2]&lt;/li&gt;
&lt;li&gt;Full cloud config synchronisation - Allows the proxy to synchronise its configuration with a central cloud service, making it easier to manage multiple proxies.
... and a &lt;a href=&quot;https://github.com/orgs/CloudinatorMC/projects/1&quot;&gt;public roadmap&lt;/a&gt; with more features to come!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;[^2]: TLS tunnelling will not be part of the &lt;code&gt;mc-router&lt;/code&gt; binary itself, instead it will be implemented as a separate sidecar service that works alongside &lt;code&gt;mc-router&lt;/code&gt;. This design choice allows for greater flexibility and modularity, enabling users to choose their preferred TLS solution without being tied to a specific implementation within the proxy.&lt;/p&gt;
&lt;h2&gt;Building &lt;code&gt;mc-router&lt;/code&gt; in Under 4 Hours&lt;/h2&gt;
&lt;p&gt;The development of &lt;a href=&quot;https://github.com/CloudinatorMC/mc-router&quot;&gt;&lt;code&gt;mc-router&lt;/code&gt;&lt;/a&gt; was a sprint, just 3 hours and 38 minutes from empty repo to a working proxy. Here’s how it unfolded:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Kickoff (16:43)&lt;/strong&gt; — &lt;a href=&quot;https://github.com/CloudinatorMC/mc-router/commit/84ae8541418c0eb75439ef71a973b1addaf607c5&quot;&gt;Commit 84ae854&lt;/a&gt; with just a README and license. I wanted a clean structure before diving into features.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Core Routing &amp;amp; UDP (18:05)&lt;/strong&gt; — &lt;a href=&quot;https://github.com/CloudinatorMC/mc-router/commit/d2de8e7716e1baf61f2f049ae3f8d6ae1fdd3d13&quot;&gt;Commit d2de8e7&lt;/a&gt; added the first working code: modular routing based on the Minecraft handshake, plus UDP forwarding to support certain mods. At this point, &lt;code&gt;mc-router&lt;/code&gt; could already pass traffic end-to-end.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real-World Usability (18:24)&lt;/strong&gt; — &lt;a href=&quot;https://github.com/CloudinatorMC/mc-router/commit/615f31b6ba7a3259ffd75bbc22329d8a1956ed2d&quot;&gt;Commit 615f31b&lt;/a&gt; added HAProxy protocol support, so backend servers see the original client IPs. I also refined the config format to make the proxy easier to operate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Toward the Cloud (20:21)&lt;/strong&gt; — &lt;a href=&quot;https://github.com/CloudinatorMC/mc-router/commit/ef4a554bb99391873df0a7cd80fb24561513b7de&quot;&gt;Commit ef4a554&lt;/a&gt; implemented the first draft of the config service API. This was the leap from &quot;just a proxy&quot; to &quot;cloud-ready infrastructure.&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The real story isn’t just &lt;a href=&quot;https://github.com/CloudinatorMC/mc-router&quot;&gt;&lt;code&gt;mc-router&lt;/code&gt;&lt;/a&gt; itself, it’s the speed at which it was built, the project took approximately 3 hours and 38 minutes from start to finish. The rapid development was made possible by leveraging GPT-5 to assist with coding tasks, allowing for quick iteration and problem-solving.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Enterprise-ready infrastructure software has traditionally required teams of engineers and weeks of development. With AI-assisted workflows, a single developer can produce production-grade systems in a single afternoon.
— ChatGPT, August 2025&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this scenario we can agree with ChatGPT&apos;s sentiment, as GPT-5 has proven it can undertake complex software development tasks efficiently. However, human oversight and expertise remain crucial to ensure the quality and reliability of the final product.&lt;/p&gt;
&lt;p&gt;The journey isn’t finished, next up is TLS tunnelling [^2] and completing the config service API backend, bringing &lt;a href=&quot;https://github.com/CloudinatorMC/mc-router&quot;&gt;&lt;code&gt;mc-router&lt;/code&gt;&lt;/a&gt; even closer to its goal of being a truly enterprise-ready ingress for Minecraft.&lt;/p&gt;
</content:encoded><author>Samuel Hulme</author></item><item><title>Designing an Automated Postal Network in Minecraft</title><link>https://samsblog.minersonline.uk/posts/designing-an-automated-postal-network-in-minecraft</link><guid isPermaLink="true">https://samsblog.minersonline.uk/posts/designing-an-automated-postal-network-in-minecraft</guid><description>Using CC: Tweaked scripting and taking inspiration from network stacks and the TCP/IP Model, we can build an automated postal network in Minecraft to transport items between locations.</description><pubDate>Sun, 21 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In Minecraft, automation is a key aspect of enhancing gameplay and efficiency. One such use is building an automated postal network that can transport items between different locations in the game. By using Lua scripting provided by the CC: Tweaked mod, we can create a system that can handle item transportation in a structured manner, inspired by real-world networking concepts like the TCP/IP Model .&lt;/p&gt;
&lt;h2&gt;How does networking relate to item transportation?&lt;/h2&gt;
&lt;p&gt;In computer networking, data is transmitted across networks using a layered approach, as defined by the TCP/IP Model . Each layer has specific responsibilities and standards, from physical transmission to application-level protocols. @cite{fortinet2025} Similarly, in Minecraft, we can think of item transportation as a multi-layered process:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Link Layer&lt;/strong&gt; &lt;em&gt;(Transport method)&lt;/em&gt;: This layer is the physical act of sending and receiving of items. Whether it is through minecart tracks, hoppers, or even Trains from the Create mod it does not matter. This is similar to how network data can travel through Ethernet cables or Wi-Fi in real-world networking. @cite{fortinet2025}&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internet Layer&lt;/strong&gt; &lt;em&gt;(Postcodes and addresses)&lt;/em&gt;: This layer ensures that items are correctly transferred to the destination by routing between networks. For Minecraft, we will create a system that uses item name addresses (&lt;a href=&quot;#package-addressing&quot;&gt;more on this later&lt;/a&gt;) to ensure that items are routed correctly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transport Layer&lt;/strong&gt; This layer is typically responsible for packet splitting, sequencing and reassembly @cite{fortinet2025}. However in Minecraft this would require automated item renaming to create individual packages, which is not possible. @cite{tweaked2025}&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Application Layer&lt;/strong&gt; &lt;em&gt;(The package contents)&lt;/em&gt;: This is the actual payload the user wants to send. In real-networking thi is the application data like HTTP, FTP, etc. @cite{fortinet2025} In our case, this is the item itself, such as diamonds, iron ingots, or any other item in Minecraft.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Package addressing&lt;/h2&gt;
&lt;p&gt;When sending items through our postal network, we need a way to address them correctly. In real-world postal systems, this is done using addresses and postcodes. In our Minecraft postal network, we will get players to rename items to include their destination address.&lt;/p&gt;
&lt;p&gt;We will use the following format where the largest geographical area is listed first, down to the most specific location:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Country:State:City:Street:HouseNumber
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The format is flexible one can include as many or as few levels as they want, but the order must be maintained. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SheepLand:Northshire:Sheepville:Wool St:1&lt;/code&gt; - A full address including country, state, city, street, and house number.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SheepLand:Northshire:Sheepville&lt;/code&gt; - A more general address that only includes the country, state, and city. This means the item will be delivered to a central location in Sheepville.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SheepLand&lt;/code&gt; - The most general address, only specifying the country. This could be used for items that are to be delivered to a central hub in the country.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Northshire:Sheepville&lt;/code&gt; - An address that omits the country, assuming it is within the same country as the sender.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Why use item names and geographical areas for addressing?&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Compatible with Minecraft&lt;/strong&gt;: Using item names for addressing is straightforward and easy to implement within the constraints of Minecraft&apos;s item system.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Supports Scripting&lt;/strong&gt;: We can programmatically read item names using Lua scripts in CC: Tweaked, making it easy to extract the address information.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Less error prone&lt;/strong&gt;: It is impossible to rename items pragmatically, so players must manually set the address with an Anvil. By choosing a human readable format, we reduce the chances of errors in addressing. Its also the very reason why DNS (Domain Name System) exists in real-world networking which turns domain names into IP addresses. @cite{fortinet2025a}&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hierarchical&lt;/strong&gt;: Using geographical areas allows for a hierarchical addressing system, similar to real-world postal systems, which can help in routing items efficiently.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backwards compatibility with existing addressing formats&lt;/strong&gt;: For example &lt;code&gt;TreeLand:dsffddfhfd7d8&lt;/code&gt; which uses a TreeLand specific format of &lt;code&gt;dsffddfhfd7d8&lt;/code&gt;, &lt;strong&gt;however one may need automated item renaming&lt;/strong&gt; to strip the global prefix once the package arrives in TreeLand, &lt;strong&gt;which is something both Minecraft or CC: Tweaked do not support&lt;/strong&gt; natively. @cite{tweaked2025}&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Address Registration and Validation&lt;/h3&gt;
&lt;p&gt;It is inevitable that players will make mistakes when renaming items. To mitigate this, we can implement a validation system that checks the address format before processing the item for delivery.&lt;/p&gt;
&lt;p&gt;We will build an address book that contains all valid geographical areas and how they are linked together. This will work similar to how routers use routing table in computer networking @cite{cloudflare2025}.&lt;/p&gt;
&lt;p&gt;When an item is processed, the system will check the address against this address book to ensure it is valid. If the address is invalid, the shipment would not be sent.&lt;/p&gt;
&lt;p&gt;Furthermore, the address book could be decentralised, meaning each location could maintain a list of neighbouring locations. This would allow for a more dynamic and scalable addressing system, as locations could be added or removed without needing to update a central database.&lt;/p&gt;
&lt;p&gt;However, this would require a protocol similar to BGP (Border Gateway Protocol) used in real-world networking to exchange routing information about which networks connect to each other. @cite{cloudflare2025}&lt;/p&gt;
&lt;h2&gt;Package assembly and transport&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Package Preparation&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;To send a item, the player would first rename it with the desired address using an Anvil. The item would then be placed into a designated &quot;outgoing&quot; chest connected to a Computer.&lt;/li&gt;
&lt;li&gt;The Computer would run a Lua script that scans the chest for items, validates their addresses using the address book.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Routing through hubs&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;The script would determine the best route for each package based on the address. This involves sending the package to the next hub in the route towards the destination.&lt;/li&gt;
&lt;li&gt;Each hub would have its own Computer running a similar script that handles incoming packages, checks their addresses, and forwards them to the next hop in the route.&lt;/li&gt;
&lt;li&gt;Form earlier, we know each hub would maintain a list of neighbouring hubs to facilitate routing known as an address book.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Final Delivery&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Once a package reaches its destination hub, the script would check if the address matches the local area. If it does, the package would be shipped to the final destination in the area, similar to how a router delivers packets to a client on a local area network.&lt;/li&gt;
&lt;li&gt;If the address does not match, the package would be stored as lost mail, and the player would need to contact the hub operator to retrieve it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion and what&apos;s next?&lt;/h2&gt;
&lt;p&gt;By taking inspiration from real-world networking concepts and using Lua scripting in CC: Tweaked, we can create an automated postal network in Minecraft that efficiently transports items between locations. This system not only enhances gameplay but also provides a fun and educational way to learn about networking principles. The next article in this series will cover the address book and routing protocols in more detail.&lt;/p&gt;
</content:encoded><author>Samuel Hulme</author></item><item><title>Increasing Context Size of Docker Model Runner The Right Way</title><link>https://samsblog.minersonline.uk/posts/increasing-context-size-of-docker-model-runner</link><guid isPermaLink="true">https://samsblog.minersonline.uk/posts/increasing-context-size-of-docker-model-runner</guid><description>Upgrading Docker Model Runner to support larger context sizes for improved model performance and capabilities, without cagent or compose files!</description><pubDate>Sun, 19 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Docker Model Runner uses a default context size of 4096 tokens, which is insufficient for many modern AI/ML applications that require larger context windows to function effectively.&lt;/p&gt;
&lt;p&gt;There are many well-documented solutions, however none are straightforward or reliable, for example there is an &lt;a href=&quot;https://jgcarmona.com/change-dmr-context-size/&quot;&gt;attempt to use &lt;code&gt;cagent&lt;/code&gt;&lt;/a&gt; with Docker Model Runner to increase context size, but in my experience the new context size is temporarily applied to the &lt;code&gt;cagent&lt;/code&gt; process only, and not applied by default to the specific model itself.&lt;/p&gt;
&lt;p&gt;However, the official Docker documentation only mentions how you can set the &lt;a href=&quot;https://docs.docker.com/ai/compose/models-and-compose/#model-configuration-options&quot;&gt;context size through compose files&lt;/a&gt;, but again, that only applies to the model instance in the compose project, not the default model context size globally.&lt;/p&gt;
&lt;p&gt;Looking at these options, one might assume that no reliable method exists to change the default context size of Docker Model Runner globally. &lt;em&gt;But let&apos;s dig deeper - there is a solution!&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Introducing the &lt;code&gt;docker-model&lt;/code&gt; CLI&lt;/h2&gt;
&lt;p&gt;There is actually a somewhat unknown CLI tool that lives in the Docker Model Runner repo. This tool allows you to manage and configure models directly, including setting the default context size for any model.&lt;/p&gt;
&lt;p&gt;Let&apos;s install the &lt;code&gt;docker-model&lt;/code&gt; CLI tool:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;First, navigate to the &lt;a href=&quot;https://github.com/docker/model-runner/&quot;&gt;Docker Model Runner repository&lt;/a&gt; with a web browser.&lt;/li&gt;
&lt;li&gt;Navigate to the Actions tab.&lt;/li&gt;
&lt;li&gt;Select the &lt;code&gt;Build model-cli&lt;/code&gt; workflow from the left sidebar.&lt;/li&gt;
&lt;li&gt;Click on the latest successful workflow run.&lt;/li&gt;
&lt;li&gt;Scroll down to the &quot;Artifacts&quot; section and download the &lt;code&gt;dist&lt;/code&gt; artifact.&lt;/li&gt;
&lt;li&gt;Extract the downloaded ZIP file to a directory of your choice.&lt;/li&gt;
&lt;li&gt;The archive will contain multiple directories for different operating systems and architectures. Navigate to the directory that matches your system (e.g., &lt;code&gt;windows-amd64&lt;/code&gt; for Windows on AMD64 architecture).&lt;/li&gt;
&lt;li&gt;Inside this directory, you will find the &lt;code&gt;docker-model&lt;/code&gt; executable. You can move this executable to any directory &lt;em&gt;(and optionally add it to your system&apos;s PATH for easier access)&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Changing the Default Context Size&lt;/h2&gt;
&lt;p&gt;If you have already installed models through Docker Desktop, then you can list the installed models using the &lt;code&gt;docker-model&lt;/code&gt; CLI:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-model.exe list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will output something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MODEL NAME  PARAMETERS  QUANTIZATION    ARCHITECTURE  MODEL ID      CREATED       SIZE
smollm3     3.08 B      IQ2_XXS/Q4_K_M  smollm3       9bff8b097a33  3 months ago  1.78 GiB
gpt-oss                                               e233e4483f51  2 months ago
phi4        14.66 B     IQ2_XXS/Q4_K_M  phi3          03c0bc8e0f5a  6 months ago  8.43 GiB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now to change the default context size of a specific model, use the &lt;code&gt;configure&lt;/code&gt; command along with the &lt;code&gt;--context-size&lt;/code&gt; flag. For example, to set the context size of the &lt;code&gt;smollm3&lt;/code&gt; model to 8192 tokens, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-model.exe configure smollm3 --context-size 8192
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Don&apos;t be fooled by the lack of command output - if it is silent then it has worked! You have successfully changed the default context size of the &lt;code&gt;smollm3&lt;/code&gt; model to 8192 tokens.&lt;/p&gt;
&lt;p&gt;The best part is that, unlike &lt;code&gt;cagent&lt;/code&gt;, which only initiates temporary sessions, and Compose, which defines per-project settings, &lt;code&gt;docker-model&lt;/code&gt; talks directly to the Model Runner daemon’s persistent configuration.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By using the &lt;code&gt;docker-model&lt;/code&gt; CLI tool, you can easily and reliably change the default context size of Docker Model Runner models without the need for complex workarounds like &lt;code&gt;cagent&lt;/code&gt; or Compose files. This method ensures that your models can handle larger context sizes globally, improving their performance and capabilities for various AI/ML applications. It&apos;s a reminder that even in well-documented systems, there are often hidden gems waiting to be discovered!&lt;/p&gt;
</content:encoded><author>Samuel Hulme</author></item><item><title>From Cubes to Kubes: Starting a Cloud-Native Foundation for Miners Online in One Month</title><link>https://samsblog.minersonline.uk/posts/from-cubes-to-kubes-starting-a-cloud-native-foundation-for-miners-online-in-one-month</link><guid isPermaLink="true">https://samsblog.minersonline.uk/posts/from-cubes-to-kubes-starting-a-cloud-native-foundation-for-miners-online-in-one-month</guid><description>A journey of transforming Miners Online from a traditional server setup to a cloud-native architecture using Kubernetes in just one month, from scratch, making use of Agones, Shulker, and Minestom.</description><pubDate>Sat, 25 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Few projects in the tech world are as exhilarating and challenging as starting brand new cloud-native architecture from scratch. In this post, I will share my experience of transforming Miners Online, my Minecraft server running since 2017, from a traditional server setup to a cloud-native architecture with a prototype Kubernetes deployment all within the span of one month.&lt;/p&gt;
&lt;h2&gt;The Beginning: Why Rebuild Everything?&lt;/h2&gt;
&lt;p&gt;For Miners Online, we have big plans for the future. The reasons are simple, to attract a player base we need something innovative, and interesting to offer.&lt;/p&gt;
&lt;p&gt;The existing infrastructure, which consisted of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;multiple repositories for each game and package&lt;/li&gt;
&lt;li&gt;on-premises CI/CD pipelines and Maven repositories&lt;/li&gt;
&lt;li&gt;manual process to deploy updates to the server&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;was becoming a bottleneck for growth and innovation.&lt;/p&gt;
&lt;p&gt;While this setup was functional, it was becoming increasingly difficult to manage and scale. With the rise of cloud-native technologies, I saw an opportunity to not only modernise our setup but also to leverage the benefits of scalability, resilience, and ease of management that Kubernetes offers.&lt;/p&gt;
&lt;h2&gt;The dependencies&lt;/h2&gt;
&lt;p&gt;Before diving into the rebuild, I took stock of the existing dependencies and tools that would be part of the new architecture:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt;: The backbone of the new architecture, providing orchestration for containerised applications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Helm&lt;/strong&gt;: For managing Kubernetes applications and simplifying deployments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Docker&lt;/strong&gt;: To containerise the various services and applications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub Actions&lt;/strong&gt;: For CI/CD pipelines to automate testing and deployment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub Container Registry&lt;/strong&gt;: To store and manage Docker images.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub Projects&lt;/strong&gt;: For project management and tracking progress.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://agones.dev/site/&quot;&gt;&lt;strong&gt;Agones&lt;/strong&gt;&lt;/a&gt;: A high-performance game server hosting solution that integrates well with Kubernetes.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://shulker.jeremylvln.fr/&quot;&gt;&lt;strong&gt;Shulker&lt;/strong&gt;&lt;/a&gt;: A Minecraft Kubernetes operator to manage Minecraft server instances.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://minestom.net/&quot;&gt;&lt;strong&gt;Minestom&lt;/strong&gt;&lt;/a&gt;: A lightweight Minecraft server implementation that allows for custom game development.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With these tools in mind, I set out to rebuild Miners Online from the ground up.&lt;/p&gt;
&lt;h2&gt;Step 1: Establishing the Monorepo&lt;/h2&gt;
&lt;p&gt;Starting on October 7th, the first step was to scrap all existing repositories and start from scratch with a monorepo approach. Whilst a nuclear option, this resulted in an empty canvas the &lt;a href=&quot;https://github.com/miners-online/monorepo&quot;&gt;&lt;strong&gt;Miners Online monorepo&lt;/strong&gt;&lt;/a&gt; which can be carefully built upon with planning &lt;em&gt;(which planning was certainly lacking before)&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I started by documenting the philosophy and structure of the monorepo, ensuring that it would be easy to navigate and maintain. This included setting up directories for each game, different services, and shared packages.&lt;/p&gt;
&lt;h2&gt;Step 2: Building the first games and packages&lt;/h2&gt;
&lt;p&gt;On the evening of October 7th, I began the process of creating the first games with Minestom and packages within the monorepo. I started with designing the lobby as it is quite minimal and can revel what shared packages are needed for other games. By October 8th, I had the lobby and a few essential packages set up including basic world management and schematic loading.&lt;/p&gt;
&lt;h2&gt;Step 3: Containerising with Docker with GitHub Actions&lt;/h2&gt;
&lt;p&gt;With the lobby and packages in place, I spent the next day (October 9th), containerising the application using Docker. I created a Dockerfile for the lobby and set up a GitHub Actions workflow to automate the build and push process to the GitHub Container Registry. This allowed for easy testing and deployment of the application.&lt;/p&gt;
&lt;h2&gt;Step 4: Further game development&lt;/h2&gt;
&lt;p&gt;Between October 10th and 12th, I made multiple improvements including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Block entity support in schematics&lt;/li&gt;
&lt;li&gt;Sign based game object creation&lt;/li&gt;
&lt;li&gt;Basic NPC implementation&lt;/li&gt;
&lt;li&gt;Environment variable support for configuration&lt;/li&gt;
&lt;li&gt;Simplification of the Docker build pipeline&lt;/li&gt;
&lt;li&gt;Demo Django project for future API services&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These enhancements were crucial for creating better game experiences and ensuring that the server could be easily configured.&lt;/p&gt;
&lt;h2&gt;Step 5: Kubernetes and Agones integration&lt;/h2&gt;
&lt;p&gt;On October 22nd, I began the process of integrating Kubernetes and Agones into the architecture. I used GitHub Copilot to generate the initial Helm charts and deployment configurations. However Copilot made many mistakes and ignored me many times, so I guided it through the correct configurations and best practices.&lt;/p&gt;
&lt;p&gt;Currently the Kubernetes deployment is in a prototype state, with game servers using Paper MC instead of Minestom for testing purposes. These will be updated to use Minestom once the game development is more mature.&lt;/p&gt;
&lt;h2&gt;Step 6: Managing Minecraft servers with Shulker&lt;/h2&gt;
&lt;p&gt;To manage the Minecraft server instances, I decided to use Shulker, a Kubernetes operator specifically designed for Minecraft.&lt;/p&gt;
&lt;p&gt;However, there is a version incompatibly between Shulker and the latest Minestom release which I resolved by submitting a &lt;a href=&quot;https://github.com/jeremylvln/Shulker/pull/1119&quot;&gt;pull request (PR) to Shulker&lt;/a&gt; - &lt;em&gt;I have already &lt;a href=&quot;https://github.com/jeremylvln/Shulker/issues?q=author%3Asamuelh2005&quot;&gt;contributed to Shulker in the past&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Shulker was stuck with an old Minestom version (the &lt;code&gt;1_21-9219e96f76&lt;/code&gt; snapshot) for a while, that did not support the latest &lt;code&gt;Auth&lt;/code&gt; API changes in Minestom. I redesigned Shulker&apos;s Minestom SDK and choose the last Minestom version (&lt;code&gt;2025.10.05-1.21.8&lt;/code&gt;) to support Java 21 - as Shulker builds with Java 21 I could not use the actual latest Minestom version (&lt;code&gt;2025.10.18-1.21.10&lt;/code&gt;) which supports Java 25+ only. &lt;strong&gt;As of writing this post, the PR is still unmerged, which means I am unable to use the Shulker SDK in my games and as a result unable to deploy any games to the cluster.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Step 7: Project management and tracking progress&lt;/h2&gt;
&lt;p&gt;On October 23rd, I set up &lt;a href=&quot;https://github.com/orgs/miners-online/projects/2&quot;&gt;a public roadmap on GitHub Projects&lt;/a&gt; to manage and track the progress of the rebuild.&lt;/p&gt;
&lt;p&gt;Introducing project management practices after most of the work was done, will help to keep future development organised and ensure that tasks are prioritised effectively.&lt;/p&gt;
&lt;p&gt;Furthermore, a public roadmap allows the community to see what is planned and contribute ideas or feedback.&lt;/p&gt;
&lt;h2&gt;Conclusion: Reflecting on the Journey&lt;/h2&gt;
&lt;p&gt;Rebuilding Miners Online from scratch into a cloud-native architecture using Kubernetes in just one month has been an intense but rewarding experience. While there is still much work to be done, the foundation has been laid for a more scalable, resilient, and manageable infrastructure.&lt;/p&gt;
&lt;p&gt;What&apos;s next? The immediate next steps involve:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Waiting for the Shulker PR to enable Minestom support&lt;/li&gt;
&lt;li&gt;Integrating the Shulker SDK into the games&lt;/li&gt;
&lt;li&gt;Testing and deploying the games to the Kubernetes cluster&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This journey has not only modernised Miners Online but also provided valuable insights into cloud-native technologies and best practices. I look forward to continuing this journey and sharing more updates in the future.&lt;/p&gt;
</content:encoded><author>Samuel Hulme</author></item></channel></rss>