A self-hosted, Docker-based home server running on Raspberry Pi 4. Includes media streaming, ad-blocking, automated downloads, photo management, and system monitoring.
- Raspberry Pi 4 (4GB or 8GB)
- SD Card for OS
- External SSD/HDD (formatted to ext4)
- Ethernet connection to router (recommended)
-
Flash Raspberry Pi OS Lite (64-bit) using Raspberry Pi Imager.
-
Enable SSH:
- Enable it in the settings before flashing
-
Connect via SSH:
ssh pi@<raspberry_ip>
-
Open the DHCP configuration file:
sudo nano /etc/dhcpcd.conf
-
Scroll to the bottom and add the following lines:
interface eth0 static ip_address=192.168.31.100/24 static routers=192.168.31.1 static domain_name_servers=1.1.1.1 8.8.8.8
Replace
192.168.31.100
with your desired static IP and192.168.31.1
with your router's IP. -
Save the file and reboot:
sudo reboot
-
Plug in your external SSD or HDD.
-
List available disks to identify your drive (usually
/dev/sda1
):lsblk
-
Format the drive to ext4 (WARNING: this erases all data on the drive):
sudo mkfs.ext4 /dev/sda1
-
Create a mount point:
sudo mkdir -p /mnt/hdd
-
Find the UUID of your drive:
sudo blkid
-
Edit the
/etc/fstab
file to auto-mount on boot:sudo nano /etc/fstab
Add this line at the end (replace
XXXX-XXXX
with your actual UUID):UUID=XXXX-XXXX /mnt/hdd ext4 defaults,noatime 0 2
-
Mount the drive immediately:
sudo mount -a
-
Update and upgrade your system:
sudo apt update && sudo apt upgrade -y
-
Install Docker using the official convenience script:
curl -sSL https://get.docker.com | sh
-
Add your user to the Docker group:
sudo usermod -aG docker $USER
Log out and back in or reboot to apply group changes.
-
Docker Compose is now included as a plugin in modern Docker versions. You can use it like this:
docker compose version
No need to install it separately. Use
docker compose
(with a space) instead ofdocker-compose
. -
Confirm installation:
docker --version docker compose version
To access your home server from outside your local network securely, use Tailscale, a zero-config WireGuard-based VPN.
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up --advertise-routes=192.168.31.0/24
This advertises your Raspberry Pi as a subnet router so you can access all local IP devices (e.g., 192.168.31.x
) from any device in your Tailscale network.
Don't forget to approve the subnet route in the Tailscale admin panel under your Pi's device settings.
Subnet routing is not required if you're okay with accessing services using only the Pi's Tailscale IP (e.g., 100.x.x.x
). In that case, you can simply use:
sudo tailscale up
tailscale status
After this, you can securely access your Raspberry Pi and local services using either its Tailscale IP (e.g.,
100.x.x.x
) or local LAN IP (e.g.,192.168.31.x
).
All services are organized in individual folders, each containing its own docker-compose.yml
file.
Create a directory for your Docker setup and clone your repository:
mkdir ~/docker
cd ~/docker
git clone https://github.com/RohitRajeshvdy/Raspi_Home_Server.git .
This will clone all folders and files from your GitHub repo into the
~/docker
directory on your Raspberry Pi.
Portainer is a web UI for managing your Docker containers and stacks.
cd ~/docker/portainer
docker compose up -d
To modify the configuration:
nano docker-compose.yml
Open your browser and go to:
http://<raspberry_pi_ip>:9000
Set your admin password to complete the initial setup.
NGINX Proxy Manager provides an easy interface to manage reverse proxies, domain names, and SSL certificates.
cd ~/docker/nginx
docker compose up -d
Access the web UI at:
http://<raspberry_pi_ip>:81
- Default login:
- Username:
[email protected]
- Password:
changeme
- Username:
- Change credentials on first login.
- Go to DuckDNS and sign in using any provider.
- Create a domain, e.g.,
yourname.duckdns.org
- Update the IP to your Raspberry Piβs local IP and copy the token.
In NGINX Proxy Manager:
- Go to SSL Certificates β Add SSL Certificate.
- Choose Letβs Encrypt, enter:
- Domain Names:
yourname.duckdns.org
,*.yourname.duckdns.org
- Enable DNS Challenge
- Choose DuckDNS
- Enter your DuckDNS token
- Domain Names:
- If validation fails, increase propagation delay to 30 seconds.
β This is a one-time certificate setup. You do not need to repeat this for other services.
- Navigate to Hosts β Proxy Hosts β Add Proxy Host
- Fill in:
- Domain Names:
portainer.yourname.duckdns.org
- Forward Hostname/IP:
<raspberry_pi_ip>
- Forward Port:
9000
- Enable:
Websockets Support
Block Common Exploits
Websockets Support
- Domain Names:
- Go to the SSL tab:
- Select the certificate you created
- Enable
Force SSL
andHTTP/2 Support
You can now access Portainer via:
https://portainer.yourname.duckdns.org
π Repeat these proxy host steps for each service you deploy below.
cd ~/docker/pihole
nano docker-compose.yml
Update the following lines:
- Change the
TZ
to your timezone (e.g.,Asia/Kolkata
) - Set a secure
WEBPASSWORD
to access the Pi-hole dashboard
Example:
environment:
- TZ=Asia/Kolkata
- WEBPASSWORD=your_strong_password
Modify other settings (like ports or volumes) only if needed.
docker compose up -d
Open your browser and visit:
http://<your-raspberry-pi-ip>:8080
Log in using the password you set in the
WEBPASSWORD
field.
Choose one of the two DNS setup options below:
- Login to your router admin panel (usually
192.168.1.1
or similar). - Find the DNS settings (under LAN or DHCP settings).
- Set the Primary DNS to your Raspberry Pi IP (e.g.,
192.168.31.100
) - Save and reboot the router.
This routes all devices on your network through Pi-hole automatically.
If router DNS change isn't possible:
- On each device (PC, mobile, etc), go to network settings.
- Manually set the DNS to your Raspberry Piβs IP (e.g.,
192.168.31.100
) - Leave the secondary DNS blank or use
1.1.1.1
as fallback (optional).
π Done! Pi-hole should now be actively blocking ads for your chosen devices.
cd ~/docker/glances
nano docker-compose.yml
Update the following line:
- Change the
TZ
to your timezone (e.g.,Asia/Kolkata
)
Example:
environment:
- TZ=Asia/Kolkata
No other changes needed unless you want to adjust port mapping or volume paths.
docker compose up -d
Open your browser and go to:
http://<your-raspberry-pi-ip>:61208
Glances provides real-time system monitoring directly in your browser.
π Done! You now have system resource monitoring via Glances.
cd ~/docker/uptime-kuma
docker compose up -d
No need to edit the compose file β it's ready to go!
Open your browser and go to:
http://<your-raspberry-pi-ip>:3001
Create an admin account on first login.
Once inside the dashboard:
- Click "Add New Monitor".
- Enter a friendly name (e.g., "Pi-hole")
- Enter the URL/IP and port (e.g.,
http://192.168.31.100:8080
) - Click "Save".
Repeat this process for each service you want to monitor (e.g., Glances, Jellyfin, qBittorrent).
π Done! Uptime Kuma is now monitoring your services and will notify you of any downtime.
β οΈ Warning: Immich is resource-heavy when Machine Learning is enabled. On a Raspberry Pi 4, it works perfectly fine without Machine Learning. You can still enable it, but expect high RAM and CPU usage.
Machine Learning in Immich enables:
- Face recognition
- Object detection
- Image classification
- Auto-tagging
If you do not need these features, it's strongly recommended to comment out the entire machine-learning
service in the docker-compose.yml
file to keep your system responsive.
cd ~/docker/immich
nano docker-compose.yml
- Locate the section starting with
machine-learning:
and comment out that entire block using#
. - Save and exit.
nano .env
Update the storage path to your mounted external drive. Example:
UPLOAD_LOCATION=/mnt/hdd/immich
Make sure this folder exists. If not, create it using:
sudo mkdir -p /mnt/hdd/immich
sudo chown -R pi:pi /mnt/hdd/immich
mkdir -p
creates the folder (including any missing parent directories).chown -R pi:pi
gives ownership of the folder (and all files inside) to thepi
user.
docker compose up -d
Open your browser and visit:
http://<your-raspberry-pi-ip>:2283
Create your admin account and start uploading and organizing your photos.
π Done! Immich is now running. Use it to back up and manage your photo library.
π§ If you ever upgrade to a more powerful server, you can re-enable the machine learning features for smarter photo organization.
Before deploying Jellyfin and Jellyseerr, create the required directory structure on your external drive:
sudo mkdir -p /mnt/hdd/data/{books,movies,shows,downloads/qbittorrent/{completed/{radarr,sonarr,unsorted},incomplete/{radarr,sonarr,unsorted},torrents}}
sudo chown -R pi:pi /mnt/hdd/data
This sets up dedicated folders for all your media content and download organization.
cd ~/docker/jellyfin
nano docker-compose.yml
Make the following changes:
- Set the correct timezone for both
jellyfin
andjellyseerr
services:
environment:
- TZ=Asia/Kolkata
- Update the volume mappings to match your Raspberry Pi setup:
volumes:
- /home/mcper/docker/jellyfin/config:/config
- /home/mcper/docker/jellyfin/cache:/cache
- /mnt/hdd/data:/media
For Jellyseerr:
volumes:
- /home/mcper/docker/jellyfin/jellyseerr/config:/app/config
These mount paths ensure your media files and configurations are persisted and accessible by both containers.
docker compose up -d
- Jellyfin:
http://<your-raspberry-pi-ip>:8096
- Jellyseerr:
http://<your-raspberry-pi-ip>:5055
Set up your admin accounts and start configuring media libraries and request handling.
π Done! Jellyfin will serve your media and Jellyseerr will help users request new content to be automatically downloaded.
This section covers installing and configuring the full *arr stack: qBittorrent, Sonarr, Radarr, Lidarr, Prowlarr, and Bazarr.
cd ~/docker/arr
nano docker-compose.yml
Ensure all services use the correct data mount:
volumes:
- /mnt/hdd/data:/data
This is required for media file access and consistent storage.
nano .env
Set your timezone and user IDs:
TZ=Asia/Kolkata
PUID=1000
PGID=1000
docker compose up -d
After the services start, check qBittorrent logs to find the default login credentials:
docker logs qbittorrent
Access the web interface:
http://<raspberry-pi-ip>:8080
Use the credentials from the logs, then immediately change them in:
Settings β Web UI β Username / Password
- Sonarr: http://:8989
- Radarr: http://:7878
- Lidarr: http://:8686
- Bazarr: http://:6767
- Prowlarr: http://:9696
All services are now running and accessible via your Piβs IP address.
For full configuration of the *arr automation system (Sonarr/Radarr + Prowlarr + qBittorrent), watch this video:
It covers indexers, download clients, and organizing your media end-to-end.
π Done! Your automated media server is live and ready to use.
cd ~/docker/homarr
docker compose up -d
No file edits required β it's plug and play.
http://<raspberry-pi-ip>:7575
- Add widgets for Jellyfin, Pi-hole, etc.
- Set logos, names, and links.
- Save the layout for quick service access.
π Homarr gives you a clean homepage to access and manage your server apps.
Create a new directory for Filebrowser:
mkdir -p ~/docker/filebrowser
cd ~/docker/filebrowser
The docker-compose.yml
file already exists. Open it and edit the Filebrowser service block to:
- Set the correct
user
ID (e.g.,1000:1000
) based on your system. - Update the
volumes
paths to point to/mnt/hdd/filebrowser/srv
,/mnt/hdd/filebrowser/config
and/mnt/hdd/filebrowser/database
.
Create required folders and assign proper permissions:
sudo mkdir -p /mnt/hdd/filebrowser/{srv,config,database}
sudo chown -R 1000:1000 /mnt/hdd/filebrowser
Ensures Filebrowser has access to read/write data and config files.
docker compose up -d
After it starts, check the container logs for default login credentials:
docker logs filebrowser
Open your browser and visit:
http://<your-raspberry-pi-ip>:8443
Log in using the credentials from the logs.
Once logged in, change the username and password via:
Settings β User Management
π Done! You now have a simple web-based file manager accessible from your browser.
Gotify is a simple self-hosted push notification server for sending real-time notifications.
cd gotify
docker compose up -d
- Username:
admin
- Password:
changeme
After first login, it's recommended to change the password for security.
You can now access Gotify via your browser at:
http://<your-raspberry-pi-ip>:8484
- Log in to the Gotify web interface.
- Go to the Applications tab.
- Click Create Application.
- Give your app a name like
uptimekuma
orwatchtower
. - Note down the generated token β this is needed for integrations.
Use this token in Uptime Kuma or Watchtower to send notifications to Gotify.
Watchtower automatically updates running Docker containers whenever their base images are refreshed.
cd watchtower
-
Open your existing
docker-compose.yml
file inside thewatchtower
directory. -
Edit the following environment variables under the
watchtower
service:WATCHTOWER_NOTIFICATION_GOTIFY_URL
: Set it to your Gotify endpoint (e.g.,https://gotify.example.duckdns.org/
).WATCHTOWER_NOTIFICATION_GOTIFY_TOKEN
: Paste the token generated from your Gotify application.WATCHTOWER_DISABLE_CONTAINERS
: List containers you do not want Watchtower to auto-update (e.g.,gotify,file-browser,portainer,...
).- You can also customize the schedule with
WATCHTOWER_SCHEDULE
(e.g.,"0 1 * * *"
for 1 AM daily).
docker compose up -d
Watchtower will now:
- Monitor running containers.
- Auto-update them based on your schedule.
- Skip the containers you've listed.
- Send update notifications to Gotify.
Coming soon...