tafseeriqbal/Homeserver-barebasics

Pi-hole, Minecraft, WebDAV and a git mirror on a 2009 laptop with 4GB memory and tailnet only access.

Shell

2

19 commits

updated Sep 21, 2026

See the code

See what people are saying

SourceMessageScoreDate

4GB Toshiba laptop running Pi-hole, Minecraft and Tailscale (r/homelab)

Just got my first server running using parts I already had lying around. Not much lowkey **Hardware** - Old Toshiba laptop, Pentium T4400, 4GB RAM (maxed out) - 256GB SATA SSD pulled from a dead HP Pavilion - Ubuntu Server 24.04 **What it runs** - **Tailscale** – the only way in. No port…

0

Oct 2, 2026

README

Running 4 services on 4GB RAM

A home server built from a 2009 Toshiba laptop. It runs Pi-hole, a Minecraft server, a small WebDAV share for my phone, and a git mirror for my notes.

Mostly notes for myself, but it should help anyone at my level getting into homelabbing. Everything here matches what's actually running on the box.

This repo is the base: the hardware, the network, security, Pi-hole and backups. The other services each have their own repo:

Anything I add later gets the bobserver topic, so that link always lists all of them.

   laptop ─┐
   phone ──┼── tailnet (WireGuard mesh) ── server ─┬─ Minecraft  :25565
  friend ──┘                                       ├─ WebDAV     :8443
                                                   └─ git mirror (outbound)

       LAN ─────────────────────────────────────── Pi-hole      :53

The hardware

  • Toshiba Satellite L500 from 2009
  • Pentium T4400, 2 cores
  • 3.8GB of usable RAM (4GB is the most it takes)
  • 256GB SSD salvaged from a damaged laptop, replacing the old hard drive
  • Ubuntu Server 24.04 LTS, no desktop, managed over SSH

What runs on it

ServiceWhat it doesRAM usedWho can reach it
Minecraft (Paper)Game server for two players2.2 GBTailnet only
DockerInstalled for later, nothing running164 MB—
TailscalePrivate network between my devices110 MB—
Pi-holeBlocks ads and bad domains for the whole house86 MBHome network
fail2banBans IPs that keep failing SSH logins37 MB—
Apache + WebDAVLets my phone drop notes onto the server12 MBTailnet only
git mirrorSyncs my notes repo every 5 minutestinyOutbound only

Total: about 2.6GB used out of 3.8GB. Measured with systemd-cgtop -m.

No ports open to the internet

I didn't forward a single port on my router. Instead, every device I own runs Tailscale. Tailscale builds a private, encrypted network between them (a "tailnet"), so my laptop and phone can reach the server from anywhere.

My friend gets in the same way. I shared the server with their Tailscale account. They don't get an account on the server itself.

Who can reach what:

  1. The internet. Can't reach anything on the server.
  2. The home network (LAN). Can use Pi-hole for DNS, and SSH in.
  3. The tailnet. Can reach Minecraft, WebDAV, SSH and the Pi-hole admin page.

The services, one by one

Minecraft

Paper on Java 25, run by systemd, tailnet only. The service file, backups, setup and everything that went wrong with it are in mc-server.

Pi-hole

DNS turns names like google.com into addresses. Pi-hole sits in the middle. When a device asks for an ad or malware domain, Pi-hole answers 0.0.0.0, which leads nowhere, so the ad never loads.

  • The router hands out the server's address as the DNS server, so every device in the house uses it with no setup
  • 4 blocklists, 244,369 entries (227,266 unique domains)
  • In one day, with only the first list loaded, it answered about 52,500 queries and blocked about 2,900
  • Pi-hole v6 uses ports 53 (DNS), 80 and 443 (its admin page)
  • The server needs a fixed address, or every device loses DNS. I set a DHCP reservation on the router

Files: scripts/setup-pihole.sh, config/pihole-blocklists.txt, config/pihole-v6-settings.txt

Phone inbox and notes sync

My phone drops notes onto the server over WebDAV. A script moves them into my notes repo every 5 minutes, and my laptop pulls them from GitHub. All of it is in org-sync.

Backups

  • Every night at 04:00, cron runs backup-run
  • backup-run runs every script in ~/.config/backup.d/. Each service links its own script in there, so adding a service never means editing this repo
  • If one script fails, the rest still run. Each run is logged to ~/.local/state/backup-run.log
  • Right now the only one is Minecraft's. How it works is in mc-server
  • Backups go to Google Drive with rclone. The rclone config has login tokens in it, so it never goes in a repo

The notes don't need this. They're a git repo, so every sync is already a backup with full history.

Files: scripts/backup-run, crontab.example

Security

  • SSH: key only. No passwords, no root login
  • Tailscale SSH: over the tailnet, SSH checks my Tailscale login instead of a key
  • fail2ban: bans IPs that keep failing to log in
  • Firewall (ufw): blocks everything coming in, except:
    • from the home network: SSH, DNS, Pi-hole admin page
    • from the tailnet: SSH, Pi-hole admin page, and whatever port each service opens for itself (Minecraft 25565, WebDAV 8443)
  • Updates: unattended-upgrades installs security patches on its own
  • My friend: can reach the Minecraft port and nothing else
  • Secrets: passwords and tokens are never in this repo. Everything personal is replaced with placeholders
  • Lid: closing the laptop lid doesn't suspend it (logind.conf)

Files: config/sshd-hardening.conf, scripts/ufw-rules.sh

Adding a service

Every service repo follows the same pattern, so a new one never touches this repo:

  1. It has an install.sh that's safe to run twice
  2. It opens its own port with ufw, on tailscale0 only
  3. If it has data worth keeping, it links a backup script into ~/.config/backup.d/
  4. Its README says which port it uses and how much RAM. Check sudo ss -tlnp and free -h before adding one
  5. It gets the bobserver topic on GitHub

Things that went wrong

Problems with Minecraft and WebDAV are written up in their own repos.

1. "Key only" SSH that still took passwords

My hardening file (99-hardening.conf) said PasswordAuthentication no. But sudo sshd -T, which shows the settings SSH is really using, said yes.

The Ubuntu installer had made a file called 50-cloud-init.conf that said yes. SSH reads the files in that folder in alphabetical order and keeps the first value it finds. 50 comes before 99, so my file lost. I renamed mine to 00-hardening.conf.

2. A firewall more open than I thought

When I compared sudo ufw status to this README, three rules were wider than I'd written down. One let every tailnet device reach every port. Others opened SSH, DNS and HTTP to anyone, including over IPv6. The server has public IPv6 addresses, so the router was the only thing stopping outside traffic. I replaced them with narrower rules.

Known gaps

  • Nothing alerts me when something breaks. I find out when I look
  • If the server goes down, DNS goes down for the whole house
  • One old laptop, one SSD, one power supply
  • No memory limits on any service
  • Docker is installed but not used yet. Careful: ports published by Docker skip ufw completely

Useful commands

sudo ufw status numbered                              # firewall rules
sudo install -d /run/sshd; sudo sshd -T | grep password   # should say "no"
sudo ss -tlnp                                         # which program uses which port
pihole status                                         # is ad blocking on?
tail ~/.local/state/backup-run.log                    # did last night's backups work?
free -h                                               # RAM use

SSH here starts on demand (ssh.socket), so /run/sshd often doesn't exist, and sshd -T refuses to run without it. Hence the install -d first.

What's in this repo

config/     SSH hardening, Pi-hole blocklists and settings
docs/       SETUP.md, step-by-step setup in the right order
scripts/    backup-run, setup-pihole.sh, ufw-rules.sh
crontab.example

Start with docs/SETUP.md. Order matters: firewall before services, Tailscale before anything that should only be reachable over the tailnet, fixed IP before Pi-hole.

Also by me

doodoo, a terminal TODO manager in C++ with ncurses.

bobserver
homelab
minecraft-serverside
old-hardware
pi-hole
pihole
self-hosted
systemd
tailscale
ubuntu-server
webdav

tafseeriqbal/Homeserver-barebasics

Pi-hole, Minecraft, WebDAV and a git mirror on a 2009 laptop with 4GB memory and tailnet only access.

Shell

2

19 commits

updated Sep 21, 2026

See the code

See what people are saying

SourceMessageScoreDate

4GB Toshiba laptop running Pi-hole, Minecraft and Tailscale (r/homelab)

Just got my first server running using parts I already had lying around. Not much lowkey **Hardware** - Old Toshiba laptop, Pentium T4400, 4GB RAM (maxed out) - 256GB SATA SSD pulled from a dead HP Pavilion - Ubuntu Server 24.04 **What it runs** - **Tailscale** – the only way in. No port…

0

Oct 2, 2026

README

Running 4 services on 4GB RAM

A home server built from a 2009 Toshiba laptop. It runs Pi-hole, a Minecraft server, a small WebDAV share for my phone, and a git mirror for my notes.

Mostly notes for myself, but it should help anyone at my level getting into homelabbing. Everything here matches what's actually running on the box.

This repo is the base: the hardware, the network, security, Pi-hole and backups. The other services each have their own repo:

Anything I add later gets the bobserver topic, so that link always lists all of them.

   laptop ─┐
   phone ──┼── tailnet (WireGuard mesh) ── server ─┬─ Minecraft  :25565
  friend ──┘                                       ├─ WebDAV     :8443
                                                   └─ git mirror (outbound)

       LAN ─────────────────────────────────────── Pi-hole      :53

The hardware

  • Toshiba Satellite L500 from 2009
  • Pentium T4400, 2 cores
  • 3.8GB of usable RAM (4GB is the most it takes)
  • 256GB SSD salvaged from a damaged laptop, replacing the old hard drive
  • Ubuntu Server 24.04 LTS, no desktop, managed over SSH

What runs on it

ServiceWhat it doesRAM usedWho can reach it
Minecraft (Paper)Game server for two players2.2 GBTailnet only
DockerInstalled for later, nothing running164 MB—
TailscalePrivate network between my devices110 MB—
Pi-holeBlocks ads and bad domains for the whole house86 MBHome network
fail2banBans IPs that keep failing SSH logins37 MB—
Apache + WebDAVLets my phone drop notes onto the server12 MBTailnet only
git mirrorSyncs my notes repo every 5 minutestinyOutbound only

Total: about 2.6GB used out of 3.8GB. Measured with systemd-cgtop -m.

No ports open to the internet

I didn't forward a single port on my router. Instead, every device I own runs Tailscale. Tailscale builds a private, encrypted network between them (a "tailnet"), so my laptop and phone can reach the server from anywhere.

My friend gets in the same way. I shared the server with their Tailscale account. They don't get an account on the server itself.

Who can reach what:

  1. The internet. Can't reach anything on the server.
  2. The home network (LAN). Can use Pi-hole for DNS, and SSH in.
  3. The tailnet. Can reach Minecraft, WebDAV, SSH and the Pi-hole admin page.

The services, one by one

Minecraft

Paper on Java 25, run by systemd, tailnet only. The service file, backups, setup and everything that went wrong with it are in mc-server.

Pi-hole

DNS turns names like google.com into addresses. Pi-hole sits in the middle. When a device asks for an ad or malware domain, Pi-hole answers 0.0.0.0, which leads nowhere, so the ad never loads.

  • The router hands out the server's address as the DNS server, so every device in the house uses it with no setup
  • 4 blocklists, 244,369 entries (227,266 unique domains)
  • In one day, with only the first list loaded, it answered about 52,500 queries and blocked about 2,900
  • Pi-hole v6 uses ports 53 (DNS), 80 and 443 (its admin page)
  • The server needs a fixed address, or every device loses DNS. I set a DHCP reservation on the router

Files: scripts/setup-pihole.sh, config/pihole-blocklists.txt, config/pihole-v6-settings.txt

Phone inbox and notes sync

My phone drops notes onto the server over WebDAV. A script moves them into my notes repo every 5 minutes, and my laptop pulls them from GitHub. All of it is in org-sync.

Backups

  • Every night at 04:00, cron runs backup-run
  • backup-run runs every script in ~/.config/backup.d/. Each service links its own script in there, so adding a service never means editing this repo
  • If one script fails, the rest still run. Each run is logged to ~/.local/state/backup-run.log
  • Right now the only one is Minecraft's. How it works is in mc-server
  • Backups go to Google Drive with rclone. The rclone config has login tokens in it, so it never goes in a repo

The notes don't need this. They're a git repo, so every sync is already a backup with full history.

Files: scripts/backup-run, crontab.example

Security

  • SSH: key only. No passwords, no root login
  • Tailscale SSH: over the tailnet, SSH checks my Tailscale login instead of a key
  • fail2ban: bans IPs that keep failing to log in
  • Firewall (ufw): blocks everything coming in, except:
    • from the home network: SSH, DNS, Pi-hole admin page
    • from the tailnet: SSH, Pi-hole admin page, and whatever port each service opens for itself (Minecraft 25565, WebDAV 8443)
  • Updates: unattended-upgrades installs security patches on its own
  • My friend: can reach the Minecraft port and nothing else
  • Secrets: passwords and tokens are never in this repo. Everything personal is replaced with placeholders
  • Lid: closing the laptop lid doesn't suspend it (logind.conf)

Files: config/sshd-hardening.conf, scripts/ufw-rules.sh

Adding a service

Every service repo follows the same pattern, so a new one never touches this repo:

  1. It has an install.sh that's safe to run twice
  2. It opens its own port with ufw, on tailscale0 only
  3. If it has data worth keeping, it links a backup script into ~/.config/backup.d/
  4. Its README says which port it uses and how much RAM. Check sudo ss -tlnp and free -h before adding one
  5. It gets the bobserver topic on GitHub

Things that went wrong

Problems with Minecraft and WebDAV are written up in their own repos.

1. "Key only" SSH that still took passwords

My hardening file (99-hardening.conf) said PasswordAuthentication no. But sudo sshd -T, which shows the settings SSH is really using, said yes.

The Ubuntu installer had made a file called 50-cloud-init.conf that said yes. SSH reads the files in that folder in alphabetical order and keeps the first value it finds. 50 comes before 99, so my file lost. I renamed mine to 00-hardening.conf.

2. A firewall more open than I thought

When I compared sudo ufw status to this README, three rules were wider than I'd written down. One let every tailnet device reach every port. Others opened SSH, DNS and HTTP to anyone, including over IPv6. The server has public IPv6 addresses, so the router was the only thing stopping outside traffic. I replaced them with narrower rules.

Known gaps

  • Nothing alerts me when something breaks. I find out when I look
  • If the server goes down, DNS goes down for the whole house
  • One old laptop, one SSD, one power supply
  • No memory limits on any service
  • Docker is installed but not used yet. Careful: ports published by Docker skip ufw completely

Useful commands

sudo ufw status numbered                              # firewall rules
sudo install -d /run/sshd; sudo sshd -T | grep password   # should say "no"
sudo ss -tlnp                                         # which program uses which port
pihole status                                         # is ad blocking on?
tail ~/.local/state/backup-run.log                    # did last night's backups work?
free -h                                               # RAM use

SSH here starts on demand (ssh.socket), so /run/sshd often doesn't exist, and sshd -T refuses to run without it. Hence the install -d first.

What's in this repo

config/     SSH hardening, Pi-hole blocklists and settings
docs/       SETUP.md, step-by-step setup in the right order
scripts/    backup-run, setup-pihole.sh, ufw-rules.sh
crontab.example

Start with docs/SETUP.md. Order matters: firewall before services, Tailscale before anything that should only be reachable over the tailnet, fixed IP before Pi-hole.

Also by me

doodoo, a terminal TODO manager in C++ with ncurses.

bobserver
homelab
minecraft-serverside
old-hardware
pi-hole
pihole
self-hosted
systemd
tailscale
ubuntu-server
webdav

Languages

Shell

100.0%