cd ~cases/remote-office.md

case 03LIVE · RUNNING AT THE CLIENT

A remote office for 19 workstations

A 19-seat office needed a new terminal server. In about a week, fully remotely, I brought it up. 19 people work in their accounting software through their own VPN, the server is invisible from the internet, and every night a copy is made that I've actually restored from to check.

Timeline
October 2026, ~1 week, fully remote
Stack
Windows Server 2022 · Hyper-V · Remote Desktop Services · WireGuard · PowerShell · SQL Server Express · AppLocker
Built by
Forge Logic
19workstations, each with its own VPN key
0open ports when scanned from outside
7nightly server copies, integrity checked automatically
2 minto restore from a copy, tested in practice
~1 wkfrom an empty server to a working office
0site visits
A remote office for 19 workstations0:29

What the client wanted

  • Thin clients in the office; everyone else connects from home over VPN.
  • Everyone works in one accounting program on an SQL database.
  • A4 invoices and receipts in another office print on the employees’ own printers.
  • In his words: “so a virus can’t wipe everything”. A failure or an infection must not reach the copies.
  • Archive copies you can get back up from quickly.
  • RDS licences monthly, not up front.
  • And separately: nothing without a request. I ask first, then do.

The solution

All of the people’s work lives in a virtual machine. The physical server only runs it and stores its copies.

Employees and the admin each come in through their own VPN. The server can’t be reached from the internet, and copies live both on the host and in the cloud.

Why it’s built this way:

  • If a virus does get through, it gets into the VM. The host and the nightly copies stay intact, and rolling back to yesterday takes 2 minutes.
  • There are two VPNs, and they’re separate. An employee’s VPN only gets them to their desktop; there’s no route from it to server management.
  • Printing goes through RDP itself. The printer at home or in the office works, and there isn’t a single driver on the server.

Development story

Everything below is in the order it happened. I made every change with a PowerShell script: before it I took a snapshot of the state, and each one had its own rollback script.

ops(infra)#01

A new server and the foundation

We rented a physical server in a data centre in the Netherlands, with licences monthly too. I put the disks into a RAID-1 mirror and synced the boot partition: if one disk dies, the server still starts. The hardware runs only Hyper-V; all of the people’s work is in the virtual machine.

fix(network)#02

An address that already belonged to someone

The virtual server couldn’t get online from the address the provider gave us. I dug in and found that another customer’s server was already using that IP. I gathered evidence with a script, sent it to support, got a new address and moved over to it.

sec(firewall)#03

Windows opened the door by itself

After Hyper-V was installed, the system went ahead and opened the management services to the whole internet. The rules for remote desktop and licensing were also set to “allow from anywhere”.

I closed it. Management now goes only through the admin VPN, the desktop only through the employees’ VPN. On top of that, emergency block rules in case someone ever opens a port by mistake. An external scan showed zero open ports.

feat(monitoring)#04

A watchdog and one-click server status

I didn’t want the next time to depend on luck. I put a watchdog on the host and the VM that checks admins, services, tasks, firewall rules and logins against a baseline every hour. The admin has an “SRV status” shortcut on the desktop: disks, backups, VPN, alerts and unknown logins on one screen.

feat(print)#05

Printing without drivers

The employee’s printer is passed through to the server by remote desktop itself and behaves like a local one. Not a single driver on the server. The receipt printer in the other office works exactly the same way.

feat(backup)#06

Backups that actually restore

Every night the whole virtual machine is exported. I keep 7 copies, check disk integrity and make sure the copies don’t fill the disk. Inside the server there are shadow copies of files three times a day, so a deleted document can be pulled back in a minute. AppLocker is in audit mode for now: first I collect a picture of what actually runs, and only then block.

Making a copy isn’t enough; you have to be able to come back up from it. The very first test restore showed a problem: the export saves the machine’s memory state, and a second copy no longer fits into the host’s memory. I worked out a procedure, and a restore now takes 2 minutes.

fix(dpi)#07

Scaling, borders and invoice printing

On laptops with 125–150% scaling, invoices printed too small. The first fix simply set everyone to 100%. Printing was fixed, but two new problems popped up: the server opened in a window with scrollbars, and people with poor eyesight couldn’t enlarge anything.

So I stopped treating everyone and treated one program: I turned on DPI compatibility mode for the accounting system on the server. Shortcuts went back to the PC’s own scaling. The server is full-screen again, everyone has their own scale, and printing stayed accurate. I checked by comparing PDFs before and after, since there was no printer at hand.

sec(audit)#08

An audit after someone else's settings

The client fine-tuned the database himself, and the watchdog reported dozens of changes. Three of them were genuinely dangerous: an employee with administrator rights; copies of the whole database open to all 19 people; a system service folder where anyone could drop a file and become admin. And the program’s firewall rules were set to “from anywhere”.

First I ran an audit without touching anything. Then I agreed every item with the client. I closed it all with one script that backed up permissions and could roll back, and checked straight away that the program and printing still worked.

What I took away

The main thing from this project: check the end of the chain, not the green checkmark.

  • A restore has to be tested, not assumed. The very first test found a problem that would have cost hours in a real outage.
  • I don’t trust default settings. Windows opened management to the whole internet by itself, so after changes I always look at the server from the outside.
  • I treat the specific problem, not everyone at once. 100% scaling for everyone broke usability, while compatibility mode for one program fixed it all.
  • I don’t do what wasn’t asked. I suggest, but the client decides, and that’s what trust rests on.

Result

The office runs on the new server. 19 people get in with one icon from home or the office, the printers print, and the server can’t be seen from outside.

Copies exist on three levels: the whole server nightly, files three times a day, the database daily to the cloud. The admin sees the state of everything in one click, and the watchdog reports any unexpected change.