{"id":92,"date":"2023-04-24T08:52:49","date_gmt":"2023-04-24T07:52:49","guid":{"rendered":"https:\/\/sonic.fabio.org.uk\/?p=92"},"modified":"2023-04-24T08:52:49","modified_gmt":"2023-04-24T07:52:49","slug":"self-hosting-with-mini-pcs-discord-bot-minecraft-server","status":"publish","type":"post","link":"https:\/\/sonic.fabio.org.uk\/?p=92","title":{"rendered":"Self-hosting with Mini PCs: Discord bot &#038; Minecraft server"},"content":{"rendered":"\n<p>Not a data science blog today! I wanted to briefly share some project ideas for self-hosting and just say that Mini PCs are great! Mini PCs can be powerful and quiet little desktops, but, they can also function as servers.<\/p>\n\n\n\n<p>I got my hands on two Intel NUCs, which are small form-factor computers. It&#8217;s just like a normal desktop but can fit in your hands (~10 x10 cm).<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" width=\"252\" height=\"252\" src=\"https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/nuc.jpg\" alt=\"\" class=\"wp-image-98\" srcset=\"https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/nuc.jpg 252w, https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/nuc-150x150.jpg 150w\" sizes=\"(max-width: 252px) 100vw, 252px\" \/><\/figure>\n\n\n\n<p>If you leave them with networking and no I\/O, they will sip power (~30 Watts) and act like a little server. <\/p>\n\n\n\n<p>NUCs and other similar mini PCs such as the Antec Asrock have many use cases. For example, host websites (like this one!), be home media servers (with Jellyfin or Plex software) and be used for Home Automation servers (and more). <\/p>\n\n\n\n<p>Below are two examples: Hosting a Discord bot and Bedrock Minecraft Server. As for software prerequisites, my NUC has Ubuntu server, Python, Docker and Docker Compose already installed.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Discord bot<\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"513\" src=\"https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/image-1024x513.png\" alt=\"\" class=\"wp-image-112\" srcset=\"https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/image-1024x513.png 1024w, https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/image-300x150.png 300w, https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/image-768x385.png 768w, https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/image-1536x769.png 1536w, https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/image.png 1787w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Let&#8217;s create our own Discord bot and self-host it. First, you want to want to visit <a href=\"https:\/\/discord.com\/developers\">https:\/\/<\/a><a rel=\"noreferrer noopener\" href=\"https:\/\/discord.com\/developers\" target=\"_blank\">discord<\/a><a href=\"https:\/\/discord.com\/developers\">.com\/developers<\/a>, create an application and add a bot. You will need to copy the token and save it somewhere safe. For permissions, it depends on the bot, but usually I enable send and read messages at the least. For Privileged Gateway Intents, I would usually enable all.<\/p>\n\n\n\n<p>A typical bot could start like this<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\" data-line=\"\">import discord\nintents = discord.Intents.all()\nintents.members = True<\/code><\/pre>\n\n\n\n<p>This gives your bot the ability to receive member-related events. Next, we could make our bot invoke commands when a user types in &#8216;$&#8217; in chat:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\" data-line=\"\">from discord.ext import commands\nclient = commands.Bot(command_prefix = &quot;$&quot;, intents = intents)\n\n@client.event\nasync def on_ready():\nprint(&#039;We have logged in as {0.user}&#039;.format(client))<\/code><\/pre>\n\n\n\n<p>The <code class=\"\" data-line=\"\">on_ready()<\/code> function will let us know when the bot is connected to Discord and ready to start processing events.<\/p>\n\n\n\n<p>If we want the bot to say hello when we type $hello in the discord server we can use &#8220;context&#8221; (ctx).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\" data-line=\"\">@client.command()\nasync def hello(ctx):\n    await ctx.send(&#039;Hello!&#039;)<\/code><\/pre>\n\n\n\n<p>Don&#8217;t forget to run the bot with your token <code class=\"\" data-line=\"\">client.run(&quot;TOKEN&quot;)<\/code>. You can add your bot to your server using the OAuth2 URL generator in the Developer Portal, ticking send and read messages, and pasting the URL into the browser<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"146\" src=\"https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/image-2-1024x146.png\" alt=\"\" class=\"wp-image-115\" srcset=\"https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/image-2-1024x146.png 1024w, https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/image-2-300x43.png 300w, https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/image-2-768x109.png 768w, https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/image-2.png 1335w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>I recommend using <code class=\"\" data-line=\"\">ctx<\/code> for sending messages &#8211; it can make things easier. The context contains information about the message that triggered the command. This includes the channel, server, and author of the message.<\/p>\n\n\n\n<p>You can run the bot with <code class=\"\" data-line=\"\">python3 name_of_bot.py<\/code> in the terminal.<\/p>\n\n\n\n<p>Check out my GitHub for a Discord bot that uses the Natural Language Toolkit (NLTK) Python package to find the most negative user (silly usage I know!). <a href=\"https:\/\/github.com\/Fabio-RibeiroB\/NLPdisrespectBOT\">Fabio-RibeiroB\/NLPdisrespectBOT: Discord Bot for Sentiment Analysis (github.com)<\/a><\/p>\n\n\n\n<p>This is not a dedicated server for my bot so let&#8217;s containerise the application and let it run in the background.<\/p>\n\n\n\n<p>I don&#8217;t want my secret token in the container in case I want to share the image so I created a <code class=\"\" data-line=\"\">.env<\/code> file with <code class=\"\" data-line=\"\">TOKEN=my_token<\/code> (ignore quotes) and add this to a <code class=\"\" data-line=\"\">.gitignore<\/code> and <code class=\"\" data-line=\"\">.dockerignore<\/code> files. In the bot script, you will then need to load the env variables using the <code class=\"\" data-line=\"\">python-dotenv<\/code> library.<\/p>\n\n\n\n<p>Our Dockerfile could look like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\" data-line=\"\">FROM python:3\nWORKDIR \/app\nCOPY . .\nRUN pip install -r requirements.txt\nCMD &#091;&quot;python&quot;, &quot;sentimental_analysis_bot.py&quot;]<\/code><\/pre>\n\n\n\n<p>This assumes you have a requirements.txt file with all your dependencies.<\/p>\n\n\n\n<p>While in the directory of the bot, let&#8217;s build the image from a Dockerfile and name it.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\" data-line=\"\">docker build -t my_container_name -f Dockerfile .\n<\/code><\/pre>\n\n\n\n<p>Now we run the image as a container and pass it to the .env file and run it in the background<\/p>\n\n\n\n<p><code class=\"\" data-line=\"\">docker run -d --env-file=.env my_container_name<\/code><\/p>\n\n\n\n<p>After entering the container I can see that there is no .env file. Great!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Minecraft Bedrock server<\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"343\" src=\"https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/image-1-1024x343.png\" alt=\"\" class=\"wp-image-113\" srcset=\"https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/image-1-1024x343.png 1024w, https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/image-1-300x101.png 300w, https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/image-1-768x257.png 768w, https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/image-1-1536x515.png 1536w, https:\/\/sonic.fabio.org.uk\/wp-content\/uploads\/2023\/04\/image-1.png 1782w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>No need to spend $5\/month on a server when you can host it yourself. Thanks to the <a href=\"https:\/\/hub.docker.com\/r\/itzg\/minecraft-bedrock-server\">itzg\/minecraft-bedrock-server &#8211; Docker Image | Docker Hub<\/a> docker image, having your own Minecraft server is not too difficult. I have only played around with the Bedrock version but I believe the Java steps are similar.<\/p>\n\n\n\n<p>You will need docker to pull the image above (see the GitHub or Docker hub page for more info) and I recommend using docker-compose to get the container up in the background (command: <code class=\"\" data-line=\"\">docker-compose up -d<\/code>). <\/p>\n\n\n\n<p>As for configurable settings, I would enable the &#8220;allow list&#8221; which specifies which players can join the server; it&#8217;s just a security feature. However, the easiest way to add people to the allow list from the terminal is not clear to me. In the end, I just entered the running container (command: <code class=\"\" data-line=\"\">sudo docker exec -it my_server_name bash<\/code>) and edit the allow list JSON by installing vim (<code class=\"\" data-line=\"\">apt update &amp;&amp; apt upgrade &amp;&amp; apt install vim<\/code>). Here is an example allowlist.json.<\/p>\n\n\n\n<p><code class=\"\" data-line=\"\">[{&quot;ignoresPlayerLimit&quot;:false,&quot;name&quot;:&quot;Your_name&quot;,&quot;xuid&quot;:&quot;Your_xuid&quot;}<\/code>]<\/p>\n\n\n\n<p>To find your xuid use this site: <a href=\"https:\/\/www.cxkes.me\/xbox\/xuid\">https:\/\/www.cxkes.me\/xbox\/xuid<\/a>.<\/p>\n\n\n\n<p>Once the container is running, you must set up <a href=\"https:\/\/www.wikihow.com\/Set-Up-Port-Forwarding-on-a-Router\" data-type=\"URL\" data-id=\"https:\/\/www.wikihow.com\/Set-Up-Port-Forwarding-on-a-Router\">port forwarding &#8211; WikiHow<\/a>  has a nice guide for doing this.<\/p>\n\n\n\n<p>Below is an example docker-compose.yml that uses itzg&#8217;s Minecraft image, and set&#8217;s the Minecraft server to be survival mode, online, have an allow_list and set the name. If you ever want to change anything you can edit this file or server.properties and restart the container. For example, you may want to allow cheats.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\" data-line=\"\">version: &#039;3.4&#039;\n\nservices:\n  bds:\n    image: itzg\/minecraft-bedrock-server\n    restart: always\n    environment:\n      EULA: &quot;TRUE&quot;\n      GAMEMODE: survival\n      DIFFICULTY: easy\n      ONLINE_MODE: &quot;true&quot;\n      ALLOW_LIST: &quot;true&quot;\n      SERVER_NAME: &quot;My World&quot;\n\n    ports:\n      - 19132:19132\/udp\n    volumes:\n      - bds:\/data\n    stdin_open: true\n    tty: true\n\nvolumes:\n  bds: {}<\/code><\/pre>\n\n\n\n<p>To join the server, make sure you are on the allow list, type the server IP (same public IP as the NUC) and the port in &#8220;add server&#8221; on Minecraft.<\/p>\n\n\n\n<p>I haven&#8217;t found a better way yet to change the allow list other than installing vim on the container and editing the allow_list.json file. Or you can just disable the allow list so any can join if you are having trouble with friends connecting.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Not a data science blog today! I wanted to briefly share some project ideas for self-hosting and just say that Mini PCs are great! Mini PCs can be powerful and quiet little desktops, but, they can also function as servers. I got my hands on two Intel NUCs, which are small form-factor computers. It&#8217;s just [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[15,13,16,14],"_links":{"self":[{"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=\/wp\/v2\/posts\/92"}],"collection":[{"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=92"}],"version-history":[{"count":12,"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=\/wp\/v2\/posts\/92\/revisions"}],"predecessor-version":[{"id":117,"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=\/wp\/v2\/posts\/92\/revisions\/117"}],"wp:attachment":[{"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=92"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=92"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=92"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}