{
"path": "/3m3zys4gkfscf",
"site": "at://did:plc:ofrbh253gwicbkc5nktqepol/site.standard.publication/3m3x4bgbsh22k",
"tags": [
"apple",
"game",
"infra"
],
"$type": "site.standard.document",
"title": "Hosting My Own Minecraft Server: Replacing Aternos with a Mac Mini",
"content": {
"$type": "pub.leaflet.content",
"pages": [
{
"$type": "pub.leaflet.pages.linearDocument",
"blocks": [
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 44,
"byteStart": 37
},
"features": [
{
"uri": "https://aternos.org",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "After several months of dealing with Aternos with the queues, the sluggishness, the general sense of unreliability, I decided to host my own Minecraft server. I already had an M2 Mac mini being my main computer and a background in breaking things until they work. This seemed like a reasonable use of time."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "Why I Gave Up on Aternos"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Aternos is fine. It does what it says. It’s free. But once the novelty of “free server hosting” wears off, the cracks start to show. The 10-minute queue before you can even start your own server is tolerable the first few times, but quickly becomes a chore. Friends couldn’t just jump in either, they had to wait for me to start it manually, usually after texting to ask why it wasn’t online. Which, to be fair, is a reasonable question."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Performance was inconsistent. Some days it worked. Other days it choked under basic load. The setup just didn’t suit how we play — irregularly, impulsively, and often without warning."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "The Stack (Probably Overthought)"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 71,
"byteStart": 62
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
},
{
"index": {
"byteEnd": 98,
"byteStart": 87
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#italic"
}
]
}
],
"plaintext": "I didn’t go the quick route. What should have been a single java -jar became this... monstrosity:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.code",
"language": "plaintext",
"plaintext": "mc.ewancroft.uk\n ↓\n Cloudflare\n ↓\n TCPShield\n ↓\n DuckDNS\n ↓\n Home Router\n ↓\n Docker Container"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Whether this is overengineered or mildly practical depends on your perspective. It works, and I haven't accidentally exposed the Mac to the entire internet (yet), so I'll take that as a success."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "Custom Domain"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 34,
"byteStart": 19
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "The server runs at mc.ewancroft.uk because I already own the apex domain and didn’t want to mess with public IPs or weird third-party subdomains. It's clean, it works, and it's easier to remember than a string of numbers."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "TCPShield"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "DDoS protection on a private server for ~10 people is obviously overkill, but TCPShield has a free tier, and it integrates cleanly with Cloudflare. It probably isn’t doing much, but it looks professional, and the setup process was surprisingly painless."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "DuckDNS"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "My IP address changes on a whim, so DuckDNS handles dynamic DNS. A tiny script checks for changes every five minutes. I keep expecting it to break or rate-limit me, but so far it hasn’t. That alone feels suspicious, but I’m not going to complain."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "Port Forwarding"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 34,
"byteStart": 29
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "Standard router config: port 25565 forwarded to the Mac. No insights here. Just a bit of tinkering, a few reboots, and the usual moment of panic when the router UI stops responding."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "Docker Container"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 66,
"byteStart": 45
},
"features": [
{
"uri": "https://github.com/itzg/docker-minecraft-server",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "This bit went smoother than expected. I used itzg/minecraft-server to containerise everything. Running the server in Docker means less hassle with system dependencies and makes it easier to roll back if something breaks."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "The image supports plugins, config tweaks, and version switching with minimal idiocy. For what it’s worth, I would do this part the same way again."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "Plugins and Preferences"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "The server runs PaperMC 1.21.1 with 4GB of RAM. That’s been enough for our group."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Plugins:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "ViaVersion / ViaBackwards (to support laggards on older clients)"
}
},
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "AxGraves (keeps items after lava-based deaths)"
}
},
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "TreeFeller / VeinMiner (cut corners without shame)"
}
},
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Backuper (because I don’t trust myself)"
}
},
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Chunky (to avoid terrain loading spikes mid-session)"
}
}
]
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 34,
"byteStart": 6
},
"features": [
{
"uri": "https://modrinth.com/resourcepack/bare-bones",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "I use the Bare Bones resource pack. It’s clean, readable, and doesn’t get in the way. The whitelist keeps out strangers, which is good, because I haven’t secured this to enterprise-level production standards and don’t intend to."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "Preventing Sleep"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "The Mac mini likes to sleep when left unattended. A few simple scripts handle this:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"content": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 10,
"byteStart": 0
},
"features": [
{
"$type": "pub.leaflet.richtext.facet#code"
}
]
}
],
"plaintext": "caffeinate runs while the server is up"
}
},
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "When the server stops, the system is allowed to sleep again"
}
}
]
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "It works. I’ve resisted the urge to add more logic, mostly because I know I’ll break it."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "Not a 24/7 Server"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "This isn’t a 24/7 setup. It’s started manually when we want to play, and shut down when we’re done. That’s usually at odd hours (like 20:43, 00:17, 14:52) whenever someone feels the need to terraform a mountain or test a new datapack."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "My typical group is entirely neurodivergent. Planning ahead is rarely an option. Everything’s spontaneous, which means the server needs to be easy to bring online with short notice - and easy to forget about for a week without something catching fire."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "It works for us."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "What Improved"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Compared to Aternos:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "No startup delay"
}
},
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "More stable performance"
}
},
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Full control over settings and plugins"
}
},
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Backups that actually happen"
}
},
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "A proper domain instead of a random link"
}
},
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "No shutdowns unless I choose to"
}
}
]
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "What I Learned"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Layered setups aren’t always overkill, but they do get complex fast"
}
},
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Docker simplifies things that would otherwise be painful"
}
},
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Automation is worth the time it saves later"
}
},
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "A subdomain makes the whole thing feel vaguely official"
}
}
]
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "More importantly, I realised I actually enjoy this kind of work. Infrastructure tinkering was never the plan, but here we are."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "What’s Next"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "I’m considering:"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.unorderedList",
"children": [
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Dedicated low-power hardware"
}
},
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Offsite backups (because I’ve had enough close calls)"
}
},
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Better monitoring (even if I’ll mostly ignore it)"
}
},
{
"content": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Multiple server instances for different world types"
}
}
]
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Or maybe I’ll just leave it as-is and play when we feel like it. That’s probably more realistic."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.header",
"level": 2,
"plaintext": "Closing"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "Moving off Aternos was the right call. The new setup isn’t perfect, but it’s fast, stable, and completely mine - which means when it breaks, I know exactly who to blame."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"plaintext": "If you’ve got spare hardware and don’t mind a bit of trial-and-error, hosting your own server is absolutely worth a go. Just keep the scope small, or you’ll wake up at 03:00 wondering whether your DNS settings broke TCPShield again."
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.horizontalRule"
}
},
{
"$type": "pub.leaflet.pages.linearDocument#block",
"block": {
"$type": "pub.leaflet.blocks.text",
"facets": [
{
"index": {
"byteEnd": 42,
"byteStart": 36
},
"features": [
{
"uri": "https://github.com/ewanc26/mc-server",
"$type": "pub.leaflet.richtext.facet#link"
}
]
}
],
"plaintext": "All scripts and config files are on GitHub if you're curious - or if you want a working setup that includes several questionable decisions."
}
}
]
}
]
},
"publishedAt": "2025-06-11T00:53:26.728Z"
}