From Windows to Proxmox: Building a Production Home Lab on a Dell OptiPlex 7090
Development

From Windows to Proxmox: Building a Production Home Lab on a Dell OptiPlex 7090

Ricardo Gil
February 16, 2026
5 min read
#Proxmox #Home Lab #Self-Hosting #Tailscale #Ubuntu #AdGuard #Linux #DevOps #Samba

Introduction

Cloud hosting is convenient β€” until you realize you're paying $50–100/month for infrastructure you already own. I had a Dell OptiPlex 7090 sitting in my office running Windows 11, handling some backend services. The setup felt fragile: everything running directly on the OS, no isolation, no proper virtualization.

So I wiped it. Replaced Windows with Proxmox VE 9.1, and in a weekend I had a proper home lab server running multiple isolated containers, network-wide DNS filtering, secure remote access from anywhere, and a network file share β€” all for $0/month in cloud costs.

Here's exactly how I did it, what I learned, and what surprised me along the way.

The Hardware

The Dell OptiPlex 7090 is an underrated home lab machine. It's widely available refurbished for $200–350 and punches well above its price. Mine came configured with:

  • CPU: Intel Core i7-10700 (8 cores / 16 threads)
  • RAM: 32GB DDR4
  • Storage: 476GB NVMe (OS drive) + 1.8TB NVMe (data drive)
  • Form factor: Small Form Factor β€” quiet and compact
  • It draws roughly 35W at idle, which matters when it's running 24/7. The dual NVMe setup turned out to be key β€” Proxmox lives on the smaller drive, and all data and container storage lives on the larger one.

    If you're looking for a new machine to run as a home lab server rather than repurposing an old one, a mini PC is worth considering. The Beelink GTi13 Ultra offers an i9-13900HK with up to 64GB RAM in a tiny, silent package β€” significantly more headroom for running multiple VMs and containers simultaneously.

    Why Proxmox?

    Proxmox VE is a bare-metal hypervisor that gives you KVM virtual machines and LXC containers managed from a web UI. It's free, enterprise-grade, and built on Debian. Key reasons to choose it:

  • LXC containers run at near-native performance with tiny overhead
  • Web UI at port 8006 makes management easy without SSH for every task
  • No subscription required for home use
  • Mature ecosystem with a large community and extensive documentation
  • The install is straightforward: download the ISO, flash to a USB drive, boot, follow the wizard. A reliable USB drive matters here β€” a Samsung 64GB USB 3.1 drive works well for this.

    After install, disable the enterprise repository (it requires a paid subscription) and add the no-subscription repo:

    bash
    # Disable enterprise repo
    echo "# disabled" > /etc/apt/sources.list.d/pve-enterprise.list

    Add no-subscription repo

    echo "deb http://download.proxmox.com/debian/pve trixie pve-no-subscription" \ > /etc/apt/sources.list.d/pve-no-subscription.list

    apt update && apt dist-upgrade -y

    Mounting the Second Drive

    My 1.8TB NVMe was formatted as exFAT from its previous life as a Windows data drive. Linux doesn't include exFAT support by default:

    bash
    apt install -y exfatprogs
    mkdir -p /mnt/data_drive
    mount -t exfat /dev/nvme1n1p2 /mnt/data_drive

    To make it survive reboots, add it to /etc/fstab:

    code
    UUID=YOUR-DRIVE-UUID /mnt/data_drive exfat defaults,nofail 0 0

    Get the UUID with blkid /dev/nvme1n1p2. The nofail flag is important β€” without it, a missing drive would prevent the system from booting.

    The Ubuntu LXC Container

    Rather than running a full VM, I created an LXC container for application workloads. LXC containers share the host kernel, so they're much lighter than VMs while still providing full process isolation.

    bash
    # Download Ubuntu 24.04 template
    pveam update
    pveam download local ubuntu-24.04-standard_24.04-2_amd64.tar.zst

    Create container (8GB disk, 2GB RAM, 2 cores)

    pct create 100 local:vztmpl/ubuntu-24.04-standard_24.04-2_amd64.tar.zst \ --hostname ubuntu \ --memory 2048 \ --cores 2 \ --net0 name=eth0,bridge=vmbr0,ip=dhcp \ --rootfs local-lvm:8

    The container gets an IP from your router's DHCP. Set a static DHCP lease for it in your router so the IP never changes.

    Bind Mounting the Data Drive

    To give the Ubuntu container access to the data drive, add a bind mount in the container config:

    bash
    pct set 100 -mp0 /mnt/data_drive,mp=/mnt/data_drive
    pct reboot 100

    This is one of the elegant things about LXC β€” you can expose host paths directly into containers without any network overhead or NFS configuration.

    Running Applications with PM2

    Inside the Ubuntu container, Node.js applications run under PM2 with cluster mode for zero-downtime restarts:

    bash
    # Install Node.js 20
    curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
    apt install -y nodejs

    Install PM2 globally

    npm install -g pm2

    Start your app

    cd ~/your-app && pm2 start ecosystem.config.js

    Save and enable autostart on reboot

    pm2 save pm2 startup

    A minimal ecosystem.config.js:

    javascript
    module.exports = {
      apps: [{
        name: 'my-app',
        script: 'src/server.js',
        instances: 2,
        exec_mode: 'cluster',
        env: {
          NODE_ENV: 'production',
          PORT: 3000
        }
      }]
    };

    nginx as Reverse Proxy

    With multiple services running on different ports, nginx ties everything together on a single port:

    bash
    apt install -y nginx

    nginx
    server {
        listen 8080;

    location /api/service-one/ { proxy_pass http://localhost:3000/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }

    location /api/service-two/ { proxy_pass http://localhost:3001/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

    Tailscale for Secure Remote Access

    Tailscale creates a zero-trust mesh VPN β€” every device gets a 100.x.x.x IP accessible from anywhere, without port forwarding or managing a VPN server.

    bash
    curl -fsSL https://tailscale.com/install.sh | sh
    tailscale up

    After authenticating, your container is immediately reachable from any of your other Tailscale devices β€” phone, laptop, wherever. No firewall rules, no dynamic DNS, no open ports on your router.

    For services that need to be publicly accessible, Tailscale Funnel provides automatic HTTPS:

    bash
    tailscale funnel 8080

    This gives you a public https://your-machine.ts.net endpoint with a free TLS certificate, backed by your home server.

    A good network switch helps if you're wiring things up properly. The TP-Link TL-SG108E 8-port managed switch is a solid affordable option for a home lab with VLAN support.

    AdGuard Home for Network-Wide DNS Filtering

    AdGuard Home runs as a DNS server that blocks ads and tracking domains for every device on your network β€” no client-side installation needed.

    The Proxmox community scripts project makes the setup a one-liner from the Proxmox host:

    bash
    bash -c "$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/ct/adguardhome.sh)"

    After the container is created, point your router's DNS server setting to the AdGuard container's IP. Every device on your network instantly gets DNS-level filtering. The query logs reveal just how many tracking domains modern apps contact β€” it's eye-opening.

    Samba File Sharing

    For accessing files on the Ubuntu container from Windows machines on the same Tailscale network:

    bash
    apt install -y samba

    Add to /etc/samba/smb.conf:

    ini
    [myfiles]
       path = /home/myuser
       browseable = yes
       read only = no
       valid users = myuser

    bash
    smbpasswd -a myuser
    systemctl restart smbd && systemctl enable smbd

    Access from Windows: \\\myfiles

    > Note: Always use password authentication (valid users, smbpasswd) rather than guest access, even on a private network.

    What's Running Now

    Here's the final state of the server after the weekend build:

    | Service | Details | |---|---| | Proxmox VE 9.1 | Hypervisor, accessible via web UI | | Ubuntu LXC | Application container, 2GB RAM | | Node.js APIs | PM2 cluster mode, auto-restart | | nginx | Reverse proxy on port 8080 | | Tailscale | Secure remote access + public HTTPS funnel | | AdGuard Home | Network-wide DNS filtering | | Samba | Authenticated file share over Tailscale | | 1.8TB data drive | exFAT, bind-mounted into container |

    Total RAM used across all containers: ~2GB out of 32GB. The server idles at around 8% CPU.

    Reliability Considerations

    One important addition for any always-on server: a UPS (uninterruptible power supply). A sudden power cut while Proxmox is writing to disk can corrupt the filesystem. The CyberPower CP1500PFCLCD provides enough runtime for a graceful shutdown and protects against power fluctuations. It's one of those things you don't think about until you need it.

    For storage reliability, if you're running critical data, consider a proper NAS alongside your server. The Synology DS220+ paired with WD Red Plus drives provides RAID redundancy that a single NVMe drive can't offer.

    Lessons Learned

    exFAT on Linux is fully supported now. exfatprogs on Debian Trixie just worked β€” no data loss, no reformatting needed.

    LXC containers are underrated. Most home lab content pushes VMs, but for Linux workloads LXC is almost always the right choice. Faster, lighter, and bind mounts make storage sharing trivial.

    Tailscale is transformative. I've configured WireGuard manually before β€” it's powerful but tedious. Tailscale handles key exchange, routing, and NAT traversal automatically, with a clean admin UI on top.

    PM2 cluster mode matters. Running Node.js in cluster mode gives zero-downtime restarts during deploys and better CPU utilization. Worth setting up from day one.

    Plan your disk layout. Be intentional about which disk is for the OS and which is for data before you start. Changing it later is annoying.

    What's Next

  • Migrating a .NET 9 API to its own dedicated LXC container
  • Moving PostgreSQL to a separate container for better isolation
  • Setting up Prometheus + Grafana for metrics across all containers
  • Automated container backups with Proxmox Backup Server
  • The total investment here was time and electricity. If you have an old PC gathering dust, Proxmox is one of the highest-value things you can do with it.

    ---

    Recommended Products

    | Product | Use Case | Link | |---|---|---| | Beelink GTi13 Ultra | New home lab server | Amazon | | TP-Link TL-SG108E | Network switch | Amazon | | CyberPower CP1500PFCLCD | UPS / power protection | Amazon | | Synology DS220+ | NAS for redundant storage | Amazon | | WD Red Plus 4TB | NAS drives | Amazon | | Samsung 64GB USB 3.1 | Bootable install drive | Amazon |

    Disclosure: Some links above are affiliate links. If you purchase through them, I may earn a small commission at no extra cost to you.

    ---

    Ricardo Gil is a Full Stack Software Engineer based in South Florida. He writes about software development, DevOps, and home lab setups.

    πŸ“¬Weekly Newsletter

    Get the best home lab & AI content

    No spam. One email per week. Unsubscribe anytime.

    Share this article