I have an old laptop from 10 years ago that has been idle for several years. I recently tidied it up and modified it, deploying a Proxmox environment on the bare metal to turn it into a simple home Homelab server.
It runs Ubuntu and FnOS virtual machines, and with intranet penetration, it can be used as a long-term online VPS, or a NAS system can be deployed to back up files and pictures.
This article will introduce the complete deployment solution of PVE + virtual machine + FRP intranet penetration + Nginx reverse proxy, which can securely expose local area network services to public domain name access.
Foreword
Proxmox Virtual Environment (PVE) is an open-source virtualization platform based on KVM. The latest version is 9.1, built on Debian13, and it is a relatively active and free virtualization platform with a good community.
The reason for not choosing to directly install the corresponding system on the bare metal is that having a virtualization platform at the bottom layer allows for convenient management, switching, and parallel execution of systems (of course, depending on the performance of the old laptop, it’s not possible to run too many in parallel). If a virtual machine system crashes, you can directly delete and recreate it or restore a snapshot in PVE, which is very convenient. It also allows me to test which NAS system is good to use at will.
Moreover, enabling hardware support for virtualization does not cause much performance loss (KVM virtualization CPU loss is usually around 2-5%), and hardware passthrough to virtual machines can be configured to further reduce loss.
Hardware Modification
My laptop is an ASUS P453UJ, with an i7 6500U CPU, 8G DDR4 memory, and a 500G HDD. In terms of expandability, it only has one SATA interface, which is occupied by the HDD, and a CD/DVD drive. It’s not possible to directly insert two hard drives.
Although it only has 8G of memory, the current memory market is extremely exaggerated, and I don’t plan to expand its memory. 8G of memory is enough for the services I want to run, and I also added an additional 8G Swap space for PVE.
CD/DVD Drive to Hard Drive Bay Modification
It’s already 2025. The original HDD had Win10 installed on it, and it took several minutes from booting up to being operable, which made me doubt my life choices. So the first step is definitely to replace it with an SSD. The CD/DVD drive is also useless, so it can be removed, and a hard drive caddy adapter for a 2.5-inch SATA drive can be bought for a few to a dozen yuan.

Additionally, I happened to have a 256G M2 NGFF SSD, which could be used to install the system, but since the laptop doesn’t have this interface, it cannot be installed directly. I needed to buy an M2 NGFF to 2.5-inch SATA hard drive enclosure.
Then, insert it into the CD/DVD drive bay. The original SATA port can be used for a separate hard drive.
Network Card Upgrade
This laptop’s built-in network card is Qualcomm QCNFA435, a mid-to-low-end network card configuration that only supports Wifi5, with 1x1 MIMO, and a maximum transmission speed of only 433Mbps.
This specification can’t fully utilize the bandwidth now; it’s like an old ox pulling a broken cart.
1 | root@homelab:~# iw dev wlp3s0 link |
The rx bitrate is only a pathetic 130MBit/s!
So, I upgraded it to an Intel AX200, which supports Wifi6, 2X2 MIMO, with a maximum speed of up to 2.4Gbps, significantly outperforming the QCNFA435. The current price is between 40-50.
Under my old Wifi5 router, the AX200 still gets a huge speed boost:
1 | root@homelab:~# iw dev wlp3s0 link |
Installing PVE
Note: Before installing PVE, please confirm that your CPU supports virtualization and that virtualization is enabled in the BIOS.
Intel: ChangeAdvanced-CPU Configuration-Intel Virtualization Technologyto Enable.
Then download the image from the official PVE website: Downloads
Find a USB flash drive and burn the image to it. It is recommended to use Ventoy, which can be used as a regular USB drive and also allows you to put ISO files into it and select to load them. This way, you don’t have to re-burn each image, similar to the Fbinstool technology used years ago, but Ventoy is even more convenient.
Additionally, when installing PVE, it is best to have the machine connected to a network cable. By default, it uses a bridged network, so it can be connected via the local network immediately after installation.
After successful installation, run screenfetch:

PVE does not come with an X environment installed by default, so it can only be accessed via a browser on a local network device using the IP, with the default port being 8006.

PVE Optimization/Configuration
Connecting to Wifi Network
Since the laptop has a built-in WLAN network card, and I don’t want the machine to be dragged by a network cable, I hope it can connect to WIFI. This way, I only need to solve the power supply issue, and I can just put it anywhere.
Network Configuration
Below, I will introduce how to connect PVE to WIFI and configure virtual machines to use NAT networking.
- Enter
ip ato view the wireless network card device name; mine iswlp3s0.

- Install Wi-Fi packages
1 | apt install -y wpasupplicant iw wireless-tools |
- Configure the WIFI to connect to and save it; multiple networks can be configured (
/etc/wpa_supplicant/wpa_supplicant.conf)
1 | ctrl_interface=/run/wpa_supplicant |
- Configure
nano /etc/network/interfaces, modify the Wi-Fi network card configuration, paying attention to replacewlp3s0with your own device name.
1 | allow-hotplug wlp3s0 |
Start, execute
ifup wlp3s0, at this point, enteringip ashould show that the Wi-Fi network card is connected to the network.Enable IP forwarding, edit
/etc/sysctl.conf
- Uncomment
#net.ipv6.conf.all.forwarding=1and save. - Uncomment
#net.ipv4.ip_forward=1and save.
Note: On the latest version of PVE (9.1), the
/etc/sysctl.conffile no longer exists. Aconffile needs to be created in the/etc/sysctl.ddirectory.
1 | root@homelab:/etc/sysctl.d# cat pve.conf |
- Modify
/etc/network/interfacesto add NAT rules forvmbr0.
1 | auto vmbr0 |
- Restart the network to connect to Wi-Fi normally and access it via the local network.
1
systemctl restart networking
Reference article: PVE Steps to Connect to Wi-Fi Using Wireless Network Card
DHCP
Although PVE has been connected to WIFI, virtual machines still cannot obtain network access because the previous configuration changed PVE’s network to NAT mode (general home WLAN network cards do not support direct bridging). A DHCP service also needs to be added in PVE to assign IPs to virtual machines.
Install isc-dhcp-server:
1 | apt install isc-dhcp-server |
Edit /etc/dhcp/dhcpd.conf:
1 | # Define the subnet, must match vmbr0's IP range |
Then start the dhcp-server:
1 | systemctl restart isc-dhcp-server |
At this point, virtual machines should be able to get an IP and connect to the internet normally.
My complete /etc/network/interface is as follows:
1 | auto lo |
NAT Port Forwarding
Because we used NAT networking when connecting to WIFI earlier, virtual machines in PVE are isolated from the physical network and cannot directly access services within the virtual machine via ip:port.
If you want to access them directly via the local area network, you also need to configure iptables for port forwarding.
For easier extension, a post-up script can be added to /etc/network/interface:
1 | auto vmbr0 |
If you want to add new port forwarding later, you only need to modify this file:
1 |
|
The function is to map the virtual machine’s port to the host’s port. For example, mapping a virtual machine (10.10.10.100:22) to the host’s 10022 port:
1 | iptables -t nat -A PREROUTING -i $WIFI_IF -p tcp --dport 10022 -j DNAT --to 10.10.10.100:22 |
Executing the script will make it effective. Since we modified /etc/network/interface earlier, it will be executed every time the networking service starts, so you don’t have to worry about it not taking effect after a reboot.
Access method: If the host’s IP on the physical router is 192.168.1.123, then you can access 192.168.1.123:10022 to reach the virtual machine (10.10.10.100:22).
Wifi Full Power Operation
By default, WLAN network cards operate in a standard power-saving mode, periodically entering sleep and only waking up when data packets need to be sent or received. However, as a device that needs to be continuously online for a long time, I want the machine to maintain the highest network stability and performance.
Therefore, the network card can be set to operate at full power by default:
1 | # View the list of network cards to find the WLAN network card; mine is wlp3s0 |
Wired Network Configuration
If you want to run with a wired connection, still based on NAT topology, then /etc/network/interface would be:
1 | auto lo |
Note: The iptables port forwarding rules also need to be modified accordingly.
One-click Optimization Script
For PVE, there are some one-click optimization scripts that can directly configure passthrough + CPU/HDD/temperature display + change sources/remove subscriptions + CPU turbo boost mode.
It’s very convenient and highly recommended: pve-diy.
1 | bash -c "$(curl -fsSL https://raw.githubusercontent.com/xiangfeidexiaohuo/pve-diy/master/pve.sh)" |
You can select and configure as needed.
Installing X Environment
Since PVE installation does not include an X environment, one can only enter the terminal. However, PVE itself relies on web configuration, which becomes very inconvenient without network access or another machine.
But PVE is based on Debian, so we can naturally install an X environment on it. The official website also provides installation methods for xfce: Developer_Workstations_with_Proxmox_VE_and_X11
In short, it’s just a few commands:
1 | apt update && apt dist-upgrade |
This way, after each boot, you can normally enter xfce. Chromium is also installed, allowing PVE to be managed locally via localhost:8006.
Disabling Lid Close Sleep
Laptops typically go to sleep when the lid is closed, so it needs to be set not to sleep, otherwise, it will become unusable when the lid is closed.
Edit /etc/systemd/logind.conf, change the following three lines to ignore, and uncomment them.
1 | # Not charging |
Built-in Battery as UPS
Since the laptop itself has a built-in battery, when the power is cut off, the laptop’s internal battery can be used as a simple UPS.
Note: I believe the greatest value of a UPS is to ensure that the system shuts down normally after an unexpected power failure, preventing data loss and hardware damage.
Install upower and set actions:
1 | vim /etc/UPower/UPower.conf |
1 | [UPower] |
Then enable the upower service and set it to start automatically on boot:
1 | root@homelab:~# systemctl start upower |
This way, when the laptop loses power and the battery capacity drops below 30%, it will automatically trigger a shutdown, ensuring that both PVE and the virtual machine environment can exit normally.
Virtual Machine Installation
I run two systems on PVE:
- Ubuntu
- FnOS. Finiu recently released a stable version; as a free domestic NAS system, its community is quite active.
You can directly enter the URL on PVE to download the image:
When creating a virtual machine, simply specify the image. The display and operations can be seen in the console of each virtual machine:
Under a NAT network, to access services within a virtual machine, port forwarding using iptables is required. See NAT Port Forwarding in the previous text for details.
Hard Drive Passthrough
Because this laptop now has two hard drives, a 256G SSD for the system and virtual machines, and a 4T hard drive specifically for data storage, I passed it through to FnOS.
You can use ls /dev/disk/by-id to view the current hard drive information:
Record the ID of the hard drive you want to passthrough, then use the following command to pass it through to the specified virtual machine:
1 | # qm set {VM_ID} -scsi2 /dev/disk/by-id/{DISK_ID} |
Then, in the virtual machine’s hardware settings, you can see this hard drive:
Integrated Graphics GVT-g Passthrough
In Finiu, if the graphics card is passed through, it can be used to accelerate AI computations in the photo library and video decoding.
PVE Configuration
The CPU in my old laptop is an i7 6500U, which is a SkyLake architecture and supports GVT-g. Intel 6th-10th generation CPUs should all be compatible.
Edit /etc/default/grub and modify the GRUB_CMDLINE_LINUX_DEFAULT parameter:
1 | GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on i915.enable_gvt=1" |
Then update Grab:
1 | update-initramfs -u -k all |
You also need to load the necessary kernel modules. Edit /etc/modules and add the following content:
1 | vfio |
Then restart PVE to check if the GRUB boot parameters have taken effect:
1 | # dmesg | grep "Command line" |
And whether the kernel module kvmgt is loaded:
1 | root@homelab:~# lsmod | grep -i kvmgt |
At this point, in PVE, first shut down the virtual machine. Edit the virtual machine’s hardware, add a PCI device, and select the integrated graphics:
In the MDev type, you can see GVTg:
Select an available one, add it, and then start the virtual machine.
Virtual Machine Configuration
SSH into the Finiu virtual machine, edit /etc/modprobe.d/i915.conf, and comment out the following content:
1 | # options i915 enable_guc=3 |
Note: The purpose of this configuration line is to enable Intel graphics card’s GuC (Graphics MicroController) and HuC (HuC MicroController) hardware acceleration features.
However, it conflicts with GVT-g, preventing Finiu from calling the integrated graphics, so it needs to be commented out, and then the virtual machine restarted.
Apply changes:
1 | update-initramfs -u -k all |
Open the Finiu App Center, search for and install the i915-sriov-dkms driver.
Restart the virtual machine, and you should see that the integrated graphics card is recognized normally:
Open the photo album, modify the AI album settings, and enable GPU computing:
Note: After using GVT-g in a virtual machine, the VNC display within PVE will no longer output, and configuration can only be done via SSH.
Intranet Penetration
In previous articles, I have detailed how to deploy an intranet penetration service on a VPS: Using frp for intranet penetration
Similarly, virtual machines running on PVE and PVE itself can use frpc to connect to a public VPS for intranet penetration services.
However, the operation method is slightly different. Recently, I have gradually packaged dependent software services into docker images and run them in containers on multiple machines, which unifies the execution environment and only requires maintaining the configuration.
So, I packaged frp into a docker image for easy deployment in various environments: frp-docker
You can build the image yourself using docker_builder in the repository, or use the prebuild version (currently the latest is 0.65.0), which supports amd64 and arm64 architectures by default and supports frpc/frps.
After importing the image, you can start it directly by specifying two parameters:
MODE: frpc or frpsARCH: amd64 or arm64
docker run startup:
1 | # frpc |
1 | # frps |
This way, intranet penetration can be run very simply, only requiring the maintenance of frpc/frps configuration files.
If new penetration ports are added, the container needs to be restarted.
Note: It is best not to directly expose ports forwarded from the intranet on the public network via the VPS. Access can be achieved through Nginx + Https + authentication.
You can specifyproxyBindAddr = "127.0.0.1"in the frps configuration to force the port to bind to localhost, preventing direct public network access.
Nginx Reverse Proxy
After we forward the service ports in PVE virtual machines to the VPS via frp, we can also use Nginx to bind domain names, enabling local network services to be accessed by domain names on the public network.
Taking FnOS as an example, I created a secondary domain name on CF: fnos.xxx.com, which resolves to the VPS’s IP.
Then, an Nginx configuration can be added on the VPS:
1 | # fnos.xxxxx.com.conf |
Then stop the nginx service and apply for a certificate:
1 | apt-get install certbot |
Then start the nginx service.
Note: For applying and automatically renewing SSL certificates, please refer to the article Deploying a self-hosted MEMOS note system#SSL Certificate.
At this point, you can access the fnos.xxxxx.com domain and then access Finiu deployed in the PVE virtual machine.
Note: If a 502 error occurs when accessing the domain, you can check the nginx logs.
1 >tail -f /var/log/nginx/error.log
If it is an SSL issue, you need to check the certificate permissions in the /etc/letsencrypt/ directory to ensure nginx can read them.
1 | ls -ld /etc/letsencrypt/ |
Then restart the nginx service.
1 | sudo nginx -s reload |
Access Finiu via domain, with HTTPS:
Summary
The complete deployment solution introduced in the article describes the process of PVE + virtual machine + FRP intranet penetration + Nginx reverse proxy, which can securely expose local area network services to public domain name access.
In my deployed service load, in most cases, the CPU is basically idle, and the power consumption is also very low:

While modifying the machine, I also cleaned the dust from the laptop. Currently, the heat dissipation pressure does not seem significant, and it has been running stably for several days without any abnormalities. It can now serve as a simple home Homelab server.
Giving old machines new life and repurposing waste is the meaning of tinkering, but the joy of tinkering is often the biggest obstacle to stability, so it’s best to stop in time when it’s good enough :).
Update Log
- 2025-12-12: Added content on integrated graphics GVT-g passthrough
- 2025-12-09: Added speed comparison before and after network card replacement, and wired network configuration
- 2025-12-04: Added Wifi network card full power operation