Transform Your Old VPS into a Smart Home Server: Host Home Assistant, AdGuard DNS, and Jellyfin Media Server
Introduction: The Untapped Potential of Idle VPS Resources
Many technology professionals and businesses maintain virtual private servers (VPS) for specific projects that eventually conclude, leaving these resources underutilized. Rather than letting these servers sit idle or incurring unnecessary costs by terminating them, there exists a compelling opportunity to transform them into powerful, integrated smart home servers. This approach not only maximizes your existing investment but also creates a centralized, self-hosted ecosystem for home automation, network management, and media consumption.
The concept of a "smart home server" extends beyond simple task automation. It represents a consolidated platform where critical services—home automation, network-level ad and tracker blocking, and personal media streaming—coexist on a single, remotely accessible instance. This architecture offers significant advantages over consumer-grade, proprietary solutions, including enhanced privacy, greater customization, reduced subscription fees, and improved reliability through professional-grade infrastructure.
This comprehensive guide will walk you through converting a standard Linux VPS into a multi-service platform hosting three essential applications: Home Assistant for comprehensive automation, AdGuard Home for network-wide DNS filtering, and Jellyfin for personal media streaming. We will address configuration, security, and integration considerations to ensure a stable, performant, and secure deployment.
Architectural Overview and Prerequisites
Before beginning implementation, understanding the architectural model and verifying your VPS meets the necessary requirements is crucial. The proposed setup utilizes containerization—specifically Docker—to isolate each service, manage dependencies cleanly, and simplify updates and maintenance. This method is superior to direct installation as it prevents library conflicts and allows each application to run in its optimized environment.
Minimum VPS Specifications:
- CPU: 2+ vCores (modern architectures like AMD EPYC or Intel Xeon provide better performance per core)
- RAM: 4 GB minimum (8 GB recommended for comfortable operation with multiple concurrent streams or complex automations)
- Storage: 40 GB+ SSD storage (additional space required for media libraries)
- Network: Stable connection with a public IPv4 address; consider the bandwidth implications for remote media streaming
- Operating System: A recent LTS release of Ubuntu Server (22.04 or 24.04) or Debian (11 or 12)
Core Technical Prerequisites:
- Full SSH root or sudo access to the VPS.
- Basic familiarity with Linux command-line operations, package management (
apt), and text editors (nanoorvim). - A registered domain name (highly recommended for secure access via HTTPS).
- Understanding of fundamental networking concepts (ports, DNS, reverse proxies).
The services will be exposed via a reverse proxy (like Nginx Proxy Manager or Traefik), which handles SSL/TLS termination, routing requests to the correct container based on the domain or subdomain. This setup is both secure and user-friendly.
Phase 1: Foundational Setup and Docker Installation
The first phase involves preparing the server environment. Start by updating the system packages and installing Docker along with Docker Compose, which will define and manage our multi-container application.
System Preparation: Connect to your VPS via SSH. Update the package lists and upgrade existing packages: sudo apt update && sudo apt upgrade -y. Reboot if a kernel update was applied.
Docker Installation: Install Docker using the official repository for consistency and easier updates. The following commands are for Ubuntu/Debian:
# Add Docker's official GPG key and repository
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -yVerify the installation with sudo docker run hello-world. Add your user to the docker group to run commands without sudo: sudo usermod -aG docker $USER. You will need to log out and back in for this change to take effect.
Project Structure: Create a dedicated directory for the smart home server configuration. A well-organized structure is vital for long-term maintenance.
mkdir ~/smart-home-server
cd ~/smart-home-server
mkdir -p {homeassistant,adguard,jellyfin,proxy}/configWithin this directory, we will create a central docker-compose.yml file to orchestrate all services.
Phase 2: Deploying Home Assistant for Automation
Home Assistant is an open-source home automation platform that puts local control and privacy first. It can integrate with thousands of devices from different vendors, creating a unified, interoperable system without relying on cloud services.
Configuration: In your project directory, create or edit the docker-compose.yml file. Add the following service definition for Home Assistant. We use the official Docker image and map the configuration directory for persistence.
version: '3'
services:
homeassistant:
container_name: homeassistant
image: "ghcr.io/home-assistant/home-assistant:stable"
volumes:
- ./homeassistant/config:/config
- /etc/localtime:/etc/localtime:ro
restart: unless-stopped
privileged: true
network_mode: hostThe network_mode: host is often recommended for Home Assistant to facilitate easy discovery of devices on the local network. However, if you plan to run all services behind a reverse proxy on the same host, you may need to adjust this and map specific ports (typically 8123).
Initialization and Access: Start the container with docker compose up -d homeassistant. The first boot will take several minutes as it creates the initial configuration. Once complete, access the web interface at http://your-vps-ip:8123 to complete the setup wizard.
Key Integration Strategies: Since your Home Assistant instance is hosted remotely, integrating local devices requires careful planning. Consider these approaches:
- VPN Tunnel: Establish a site-to-site VPN (like WireGuard or Tailscale) between your VPS and your home router. This creates a secure, encrypted bridge, allowing Home Assistant to communicate with devices as if it were local.
- Cloud-Enabled Devices: For devices that require cloud APIs (like Tuya, Philips Hue), use the corresponding Home Assistant integrations. Your VPS instance will communicate with the vendor's cloud, eliminating the need for local network access.
- Remote Proxies: Use a lightweight agent (e.g., ESPHome or a dedicated Raspberry Pi running the Home Assistant Agent) within your home network to bridge communications to the remote server.
This remote architecture is particularly powerful for controlling cloud-native services, performing data logging, and sending notifications, while more latency-sensitive local automation might benefit from a hybrid model.
Phase 3: Implementing AdGuard Home for Network Security
AdGuard Home is a network-wide software for blocking ads, tracking, and malware. By hosting it on your VPS, you can configure your router (or individual devices) to use it as a DNS server, protecting all network traffic—even on mobile devices away from home when using a VPN back to your server.
Configuration: Add the AdGuard Home service to your docker-compose.yml file. We map its configuration and data volumes and expose its default ports (53 for DNS, 80/443 for the web UI, though the web UI will later be accessed via our reverse proxy).
adguard:
container_name: adguard
image: adguard/adguardhome:latest
container_name: adguardhome
volumes:
- ./adguard/work:/opt/adguardhome/work
- ./adguard/conf:/opt/adguardhome/conf
ports:
- "53:53/tcp"
- "53:53/udp"
- "784:784/udp" # QUIC
- "853:853/tcp" # DNS-over-TLS
- "3000:3000/tcp" # Temporary admin UI port
restart: unless-stoppedInitial Setup: Start the container (docker compose up -d adguard) and navigate to http://your-vps-ip:3000. Follow the setup wizard to configure the admin interface on port 80 (or another port) and set up your admin credentials. Critical Step: During setup, change the "Listen interface" for the DNS server from 0.0.0.0 to your VPS's private IP address or a Docker network IP if you plan to restrict access. Leaving it on 0.0.0.0 could expose your DNS server to the public internet, potentially leading to its abuse as an open resolver.
Deployment and Use: After setup, you can stop publishing port 3000 directly and instead access the AdGuard Home admin interface through the reverse proxy (e.g., adguard.yourdomain.com). To use it, change the DNS settings on your router to point to your VPS's public IP address. For remote use, configure your device's DNS manually or use a VPN that routes DNS queries to your VPS.
AdGuard Home's filtering provides a cleaner, faster, and more private browsing experience across all connected devices and significantly reduces the data collected by advertising networks.
Phase 4: Setting Up Jellyfin Media Server
Jellyfin is a free, open-source media server that organizes your personal video, audio, and photo collections and streams them to any device. Hosting it on a VPS allows you to access your media library from anywhere without relying on commercial services like Plex or Emby, which often have premium feature paywalls.
Configuration: Add the Jellyfin service to your Docker Compose file. Note the use of user/group ID mappings (PUID/PGID) for proper file permission handling, especially if you mount media volumes from network storage.
jellyfin:
container_name: jellyfin
image: jellyfin/jellyfin:latest
user: "1000:1000" # Match your VPS user's UID:GID
volumes:
- ./jellyfin/config:/config
- ./jellyfin/cache:/cache
- /path/to/your/media:/media:ro # Mount your media library read-only
ports:
- "8096:8096" # HTTP port
restart: unless-stoppedMedia Library Management: The primary challenge of a remote Jellyfin server is sourcing media. You have several options:
- Direct Attached Storage: Use the VPS provider's block storage volumes. This is simple but can be expensive for large libraries.
- Cloud Storage Sync: Mount a cloud storage bucket (like AWS S3, Backblaze B2, or Wasabi) using
rclone. This offers scalability but may incur egress fees. - Hybrid Approach: Keep a primary media library at home and use synchronization tools (
rsync, Syncthing) to copy new content to the VPS periodically. This balances cost and accessibility.
Optimization: Enable hardware transcoding if your VPS provider offers GPU instances (though this is rare and costly). Alternatively, pre-transcode media into universally compatible formats (like H.264 in MP4 containers) to minimize the need for live transcoding. Configure Jellyfin's library scans and metadata downloads to run during off-peak hours to conserve resources.
Phase 5: Unifying Access with a Reverse Proxy and Security
Exposing multiple services on different ports is insecure and inconvenient. A reverse proxy acts as a single entry point, routing traffic to the appropriate backend service based on the hostname. It also centralizes SSL/TLS certificate management via Let's Encrypt.
Implementing Nginx Proxy Manager: This user-friendly tool is ideal for this setup. Add it to your docker-compose.yml:
nginx-proxy-manager:
image: 'jc21/nginx-proxy-manager:latest'
container_name: nginx-proxy-manager
ports:
- '80:80'
- '443:443'
- '81:81' # Admin interface
volumes:
- ./proxy/data:/data
- ./proxy/letsencrypt:/etc/letsencrypt
restart: unless-stoppedStart the container and access the admin panel at http://your-vps-ip:81. The default login is [email protected] / changeme—change this immediately.
Configuring Proxy Hosts: For each service (Home Assistant, AdGuard Home admin, Jellyfin), create a new "Proxy Host." Point the domain (e.g., ha.yourdomain.com) to the corresponding container's internal IP and port (e.g., homeassistant:8123). Request a SSL certificate for each host using the built-in Let's Encrypt integration, forcing HTTPS redirection.
Critical Security Hardening:
- Firewall: Configure your VPS firewall (UFW) to allow only ports 80, 443, and 22 (SSH). Block all other incoming ports.
- Fail2ban: Install and configure Fail2ban to protect against brute-force attacks on SSH and your web services.
- Regular Updates: Establish a cron job for automatic security updates:
sudo apt-get update && sudo apt-get upgrade -y. - Backups: Regularly back up the
~/smart-home-serverdirectory, especially theconfigsubdirectories for each service. Usedocker-composefiles for easy redeployment.
Conclusion: Achieving a Professional, Integrated Home Ecosystem
Transforming an idle VPS into a consolidated smart home server represents a significant step toward technological self-sufficiency. This setup delivers tangible benefits: enhanced privacy through local or self-hosted services, reduced ongoing costs by eliminating multiple subscriptions, improved reliability via professional infrastructure, and unmatched flexibility for customization and expansion.
The journey from separate, consumer-grade products to an integrated, professional platform requires initial investment in setup and learning. However, the long-term payoff in control, capability, and cost-efficiency is substantial. This architecture is not static; it serves as a foundation. You can extend it with additional containers for file synchronization (Nextcloud), password management (Vaultwarden), monitoring (Grafana), or smart home bridges (Zigbee2MQTT).
By leveraging containerization and modern DevOps practices, you manage a complex system with simplicity and resilience. Your old VPS is no longer a relic of a past project but has become the intelligent, secure, and powerful core of your digital life.
