Office VPN for CCTV: Access Cameras and NVRs Without Public IPs

Was this helpful?

You want to pull up a live camera view from home, or give a regional manager access to an NVR, but the site has no public IP, no appetite for inbound firewall rules, and no desire to be tomorrow’s headline. Classic.

The good news: this is one of those problems the industry already solved. The bad news: people keep re-inventing it with vendor clouds, random port forwards, and prayers. Let’s build the boring, correct thing: an office VPN that reaches CCTV devices cleanly—without exposing them to the public internet.

What you’re actually building (and what you’re not)

“Access cameras/NVR without public IPs” is not a feature request. It’s a topology problem, plus an authentication problem, plus a “don’t melt the uplink” problem.

What you’re building is an overlay network (VPN) that provides:

  • Reachability: A stable route from an operator’s laptop (or office network) to the camera VLAN/NVR subnet.
  • Identity: A way to tell who is connecting (and to stop former employees from “just checking one thing”).
  • Policy: Rules that allow only needed ports and only needed destinations.
  • Observability: Logs and metrics so you can prove it works, and quickly diagnose when it doesn’t.

What you’re not building:

  • A public-facing web portal that forwards camera UI ports to the world.
  • A “quick port forward” to RTSP/HTTP because someone is in a hurry.
  • A vendor cloud dependency that quietly becomes your perimeter.

Here’s the blunt truth: most CCTV devices are not defensible on the public internet. Even the decent ones ship with weird services, stale OpenSSL, and UI code that makes your browser do questionable things. Give them private space, put a bouncer at the door, and make the bouncer sober.

One short joke, as promised and rationed: The fastest way to “secure” a camera is to unplug it—also the fastest way to get a call from Facilities.

Interesting facts and short history that matter

These are not trivia-night flexes. Each of these nudges your design decisions.

  1. NAT was a stopgap: Network Address Translation became common in the mid-1990s mainly because IPv4 address exhaustion was already biting. VPNs grew up in a world where “no public IP” became normal, not exceptional.
  2. IPsec predates most IP cameras: IPsec was standardized in the late 1990s, long before commodity CCTV deployments exploded. The tooling is mature, but operational complexity is real.
  3. RTSP is older than most camera firmware: RTSP (late 1990s) remains the core protocol for many camera streams. It works; it’s also easy to leak if you route it poorly.
  4. UPnP was designed for convenience: It made consumer networks “just work” by punching holes in NAT. In CCTV deployments, UPnP is how you accidentally publish an NVR admin UI to the internet.
  5. Default credentials were once normal: Early embedded devices shipped with “admin/admin” as a cultural norm. Many modern devices improved, but the ecosystem still carries that legacy.
  6. Botnets loved cameras: Large-scale botnets historically recruited DVRs/NVRs and cameras because they were reachable, underpatched, and always on. If your access method makes them reachable, you’re volunteering them.
  7. “P2P camera cloud” is basically NAT traversal: Many vendors rely on outbound connections to a rendezvous service to avoid public IPs. It’s clever, but it also means your perimeter includes a third party and their account system.
  8. WireGuard is intentionally minimal: It was designed to reduce configuration footguns and code size. That matters when you want reliable ops, not a weekly “why did the tunnel stop” séance.
  9. Most incidents are routing, not crypto: In production, VPN cryptography usually works. What fails is route propagation, asymmetric paths, DNS confusion, and someone forgetting that the camera VLAN exists.

Reference designs: pick one and commit

You have three sane patterns. Choose based on scale, trust boundaries, and who controls the network edge at each CCTV site.

Design A: Hub-and-spoke remote access (office or cloud as hub)

This is the workhorse. Each site establishes an outbound VPN tunnel to a hub (office firewall, or a small VM in a cloud VPC). Remote users connect to the hub, then route to sites.

Pros: One stable public endpoint (the hub). No inbound rules at sites. Central logging and policy.

Cons: Hub becomes a critical dependency. You must capacity-plan it. You must enforce least privilege so a single user doesn’t get the keys to every site.

Design B: Site-to-site VPN between office and camera sites

Classic IPsec or WireGuard site-to-site. Users sit in the office network; the office routes to camera subnets over tunnels.

Pros: Cleaner when all viewing happens from corporate networks (SOC, security team). Minimal client software sprawl.

Cons: Doesn’t help remote individuals unless they first VPN into the office. And yes, that can be fine—just admit that’s the plan.

Design C: Zero-trust style access (identity proxy to NVR UI)

You expose one internal UI (usually the NVR web app) through an identity-aware proxy. Cameras stay private; the proxy enforces SSO/MFA and policy.

Pros: Strong identity controls. No broad network access. Great audit story.

Cons: Harder for raw RTSP viewing, ONVIF discovery, or tooling that expects L2-ish reachability. Some NVR apps behave badly behind proxies.

For most mid-size enterprises and multi-site retail/industrial setups, I recommend Design A (hub-and-spoke) with WireGuard, plus strict firewall policy between VPN clients and camera VLANs. It’s boring in the best way.

Security model: treat cameras like hostile IoT

Assume every camera/NVR is:

  • running outdated packages,
  • shipping with too many services open,
  • logging poorly,
  • and occasionally doing “phone home” traffic you didn’t ask for.

So your design goal is not just “make it reachable.” It’s “make it reachable only through controlled paths and only for approved users.”

Hard rules that keep you out of trouble

  • No direct inbound from the internet to CCTV subnets. If you must publish something, publish an authenticated proxy, not a camera port.
  • Separate CCTV from corporate endpoints. VLAN/subnet separation with firewall rules. Cameras don’t need to talk to payroll.
  • Don’t full-tunnel video unless you mean it. A few 8 Mbps streams will turn your VPN into a slide deck. Use split tunneling with explicit routes.
  • Lock down management ports. Allow RTSP only to viewing stations, allow HTTPS only to admins, block SMB/Telnet/FTP (yes, they still show up).
  • Make identity real. Per-user keys/certs, MFA on the VPN or upstream identity system, and quick revocation.
  • Log at the choke point. The hub should be where you can answer: who accessed what NVR, when, and from where.

One quote, used sparingly because quotes are often a substitute for thinking: Hope is not a strategy. — James Cameron

WireGuard walkthrough: hub-and-spoke done right

WireGuard is a good fit for CCTV access because it’s stable under NAT, fast, and has a small configuration surface. It does not do user management for you; you’ll need a plan for key lifecycle, access control, and auditing.

Network layout example

  • Hub (public IP): 203.0.113.10, WireGuard interface wg0 with VPN subnet 10.44.0.0/24
  • Site A (no public IP): camera VLAN 10.10.50.0/24, site router runs WireGuard client with VPN IP 10.44.0.10
  • Remote user: laptop WireGuard client with VPN IP 10.44.0.101

Key idea: the site router establishes an outbound tunnel to the hub. The remote user also connects to the hub. The hub routes between them, but only as permitted by firewall rules.

Routing: make paths explicit

Do not rely on “it sort of works.” Make the hub know which site owns which camera subnet.

  • Hub has a route to 10.10.50.0/24 via peer 10.44.0.10
  • Remote user receives (or locally configures) a route to 10.10.50.0/24 via wg0
  • Site router has a route back to the VPN subnet 10.44.0.0/24 via WireGuard

Firewall policy: constrain by destination and port

At the hub, treat the VPN interface like an untrusted network. Because it is. Allow only what you need:

  • HTTPS to NVR web UI (often 443 or a vendor port)
  • RTSP to NVR/cameras (554 or vendor-defined)
  • ONVIF (commonly 80/8899/3702 UDP, varies wildly)

Block everything else, especially lateral movement between sites.

DNS: your users will type names, not subnets

If you want “nvr-site-a.corp” to resolve over VPN, you need split DNS or a VPN DNS server. Do not hack this with public DNS records pointing to private IPs unless you like confusing laptops in hotels.

Identity and access

WireGuard is key-based. That’s good. But you still need:

  • Per-user keys (no shared “security-team.conf”)
  • Key rotation and revocation process
  • MFA somewhere: either at an upstream VPN gateway (if WireGuard is behind a portal), or by issuing short-lived access via an identity broker/SSO flow. If you can’t do MFA on WireGuard directly, you can still do MFA on the system that distributes configs and controls who gets them.

Second short joke, last one: A shared VPN key is like a shared toothbrush—technically it works, but you’ll regret it.

Practical tasks with commands: verify, decide, fix

This section is deliberately hands-on. Each task includes: a command, example output, what it means, and the decision you make from it. All examples assume Linux on the hub; adapt as needed.

Task 1: Confirm WireGuard interface is up and peers are handshaking

cr0x@server:~$ sudo wg show
interface: wg0
  public key: 2qv...Zk=
  listening port: 51820

peer: 9mR...aQ=
  endpoint: 198.51.100.23:54321
  allowed ips: 10.44.0.10/32, 10.10.50.0/24
  latest handshake: 31 seconds ago
  transfer: 1.23 MiB received, 4.80 MiB sent

peer: Q1s...p8=
  endpoint: 203.0.113.77:61112
  allowed ips: 10.44.0.101/32
  latest handshake: 12 seconds ago
  transfer: 62.1 MiB received, 140.2 MiB sent

Meaning: “latest handshake” tells you liveness. If it’s minutes/hours, the tunnel is down or idle without keepalive.

Decision: If a site behind NAT goes stale, configure PersistentKeepalive=25 on that peer (site side). If the endpoint IP keeps changing, confirm the NAT device behavior.

Task 2: Validate kernel IP forwarding on the hub

cr0x@server:~$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1

Meaning: If this is 0, the hub won’t route traffic between VPN peers and site subnets.

Decision: Set it to 1 and persist in /etc/sysctl.conf or a drop-in.

Task 3: Check the route to the camera subnet exists on the hub

cr0x@server:~$ ip route show | grep 10.10.50.0
10.10.50.0/24 dev wg0 proto static scope link

Meaning: The hub believes 10.10.50.0/24 is reachable via wg0. If you don’t see it, you likely didn’t include that subnet in the site peer’s AllowedIPs on the hub.

Decision: Add the subnet to the peer’s AllowedIPs (on the hub config) so the hub knows where to send traffic.

Task 4: Confirm hub firewall allows forwarding from VPN clients to the site subnet

cr0x@server:~$ sudo nft list ruleset | sed -n '1,140p'
table inet filter {
  chain forward {
    type filter hook forward priority filter; policy drop;
    iifname "wg0" oifname "wg0" ip saddr 10.44.0.0/24 ip daddr 10.10.50.0/24 tcp dport { 443, 554 } accept
    iifname "wg0" oifname "wg0" ct state established,related accept
    counter packets 12034 bytes 9440221 drop
  }
}

Meaning: Policy is drop by default. Only TCP 443 and 554 to the camera subnet are allowed from VPN clients.

Decision: If users need ONVIF discovery, you may need specific UDP allowances, but add them intentionally and verify impact.

Task 5: Test reachability to an NVR from the hub (ICMP)

cr0x@server:~$ ping -c 3 10.10.50.20
PING 10.10.50.20 (10.10.50.20) 56(84) bytes of data.
64 bytes from 10.10.50.20: icmp_seq=1 ttl=63 time=32.1 ms
64 bytes from 10.10.50.20: icmp_seq=2 ttl=63 time=31.4 ms
64 bytes from 10.10.50.20: icmp_seq=3 ttl=63 time=31.8 ms

--- 10.10.50.20 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 31.4/31.8/32.1/0.3 ms

Meaning: Basic routing works hub → site. If ping fails but TCP works, ICMP might be blocked on the site firewall. That’s not automatically wrong.

Decision: Don’t demand ping as a “must.” Prefer service checks (HTTPS/RTSP) as the real proof.

Task 6: Verify service ports from the hub (HTTPS and RTSP)

cr0x@server:~$ nc -vz 10.10.50.20 443
Connection to 10.10.50.20 443 port [tcp/https] succeeded!
cr0x@server:~$ nc -vz 10.10.50.20 554
Connection to 10.10.50.20 554 port [tcp/rtsp] succeeded!

Meaning: The ports are reachable. If HTTPS succeeds but RTSP fails, you likely forgot to allow 554, or the NVR streams on a different port.

Decision: Adjust firewall rules to match actual vendor port usage, and document it. “Open all ports” is not documentation.

Task 7: Check that the site router is actually routing traffic from VPN to camera VLAN (from hub)

cr0x@server:~$ traceroute -n 10.10.50.20
traceroute to 10.10.50.20 (10.10.50.20), 30 hops max, 60 byte packets
 1  10.44.0.10  29.817 ms  30.101 ms  30.229 ms
 2  10.10.50.20  31.212 ms  31.444 ms  31.389 ms

Meaning: Hop 1 is the site WireGuard endpoint (router), hop 2 is the NVR. That’s the expected path.

Decision: If you see the trace stop at hop 1, the site router isn’t forwarding to the VLAN or has a firewall dropping it. Fix at the site edge, not at the hub.

Task 8: Validate reverse path (site subnet can return to VPN clients)

cr0x@server:~$ sudo tcpdump -ni wg0 host 10.10.50.20 and tcp port 443 -c 6
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on wg0, link-type RAW (Raw IP), snapshot length 262144 bytes
12:11:01.102345 IP 10.44.0.101.51722 > 10.10.50.20.443: Flags [S], seq 3011221, win 64240, options [mss 1360,sackOK,TS val 101 ecr 0], length 0
12:11:01.135902 IP 10.10.50.20.443 > 10.44.0.101.51722: Flags [S.], seq 8899102, ack 3011222, win 65160, options [mss 1360,sackOK,TS val 200 ecr 101], length 0
12:11:01.136120 IP 10.44.0.101.51722 > 10.10.50.20.443: Flags [.], ack 1, win 502, options [TS val 102 ecr 200], length 0

Meaning: You see SYN, SYN-ACK, ACK. That proves return traffic is coming back through the tunnel. If you only see SYNs with no SYN-ACK, the site side doesn’t have a route back or is blocking.

Decision: Add/repair route on the site router for 10.44.0.0/24 via wg0, or fix site firewall/NAT rules.

Task 9: Check MTU issues (the “everything connects but video stutters” classic)

cr0x@server:~$ ping -c 3 -M do -s 1372 10.10.50.20
PING 10.10.50.20 (10.10.50.20) 1372(1400) bytes of data.
1372 bytes from 10.10.50.20: icmp_seq=1 ttl=63 time=32.4 ms
1372 bytes from 10.10.50.20: icmp_seq=2 ttl=63 time=32.0 ms
1372 bytes from 10.10.50.20: icmp_seq=3 ttl=63 time=32.3 ms

--- 10.10.50.20 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms

Meaning: With DF set (-M do), packets of size 1400 work end-to-end. If this fails at a certain size, you have path MTU constraints (common with PPPoE, LTE, or stacked encapsulation).

Decision: Lower WireGuard MTU (for example to 1360 or 1280) on clients/site routers, then re-test stability.

Task 10: Watch bandwidth and identify the actual hog

cr0x@server:~$ ip -s link show dev wg0
6: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/none
    RX:  bytes packets errors dropped  missed   mcast
      987654321  902341      0      12       0       0
    TX:  bytes packets errors dropped carrier collsns
      1928374650 1102341      0      18       0       0

Meaning: Rising drops under load correlate with buffering issues or CPU saturation. Combine with CPU stats and interface counters.

Decision: If drops climb during viewing, rate-limit streams, reduce concurrent streams, or scale hub CPU/instance size. VPNs don’t invent bandwidth.

Task 11: Verify DNS resolution behavior for NVR names

cr0x@server:~$ resolvectl status | sed -n '1,80p'
Global
       Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
 resolv.conf mode: stub
Current DNS Server: 10.44.0.1
       DNS Servers: 10.44.0.1

Link 3 (wg0)
Current Scopes: DNS
     Protocols: +DefaultRoute -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
   DNS Servers: 10.44.0.1
    DNS Domain: corp.internal

Meaning: DNS is set to a VPN-side resolver (10.44.0.1) and scoped to the VPN interface. That prevents “public Wi‑Fi DNS guesses your private names wrong.”

Decision: If names don’t resolve, fix split DNS: either push DNS via VPN client config or run a resolver reachable on the VPN.

Task 12: Confirm you’re not accidentally hairpinning video through the office WAN

cr0x@server:~$ sudo conntrack -L | grep 10.10.50.20 | head
tcp      6 431999 ESTABLISHED src=10.44.0.101 dst=10.10.50.20 sport=51722 dport=443 src=10.10.50.20 dst=10.44.0.101 sport=443 dport=51722 [ASSURED] mark=0 use=1
tcp      6 431999 ESTABLISHED src=10.44.0.101 dst=10.10.50.20 sport=54012 dport=554 src=10.10.50.20 dst=10.44.0.101 sport=554 dport=54012 [ASSURED] mark=0 use=1

Meaning: You see VPN client IP to NVR IP directly, not NATed into some other subnet. That’s good; it keeps policy intelligible and logs useful.

Decision: If you see NAT you didn’t intend, audit iptables/nft NAT rules and remove “temporary” masquerade rules that became permanent.

Task 13: Prove the site’s camera VLAN isn’t routing to the internet via the VPN (yes, it happens)

cr0x@server:~$ sudo wg show wg0 allowed-ips
peer: 9mR...aQ=
  allowed ips: 10.44.0.10/32, 10.10.50.0/24
peer: Q1s...p8=
  allowed ips: 10.44.0.101/32

Meaning: The site peer is only allowed to announce its VPN IP and its camera subnet. If you ever see 0.0.0.0/0 or broad corporate ranges here without a reason, someone is turning your VPN into a default route.

Decision: Keep AllowedIPs tight. If you need more subnets, list them explicitly and review the blast radius.

Task 14: Validate time sync (because TLS and logs are useless when time is wrong)

cr0x@server:~$ timedatectl
               Local time: Sun 2025-12-28 11:52:18 UTC
           Universal time: Sun 2025-12-28 11:52:18 UTC
                 RTC time: Sun 2025-12-28 11:52:18
                Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

Meaning: Synchronized time makes your audit trail defensible and avoids “TLS cert not yet valid/expired” surprises when proxying NVR UIs.

Decision: Fix NTP everywhere you can (hub, site routers, NVRs if supported). If devices can’t do NTP reliably, account for it in incident response.

Fast diagnosis playbook

When “camera access is broken,” you can lose hours bouncing between teams. Don’t. Use a tight sequence that narrows the bottleneck quickly.

First: Is the tunnel alive?

  • Check wg show on the hub: do you have a recent handshake for the site peer and the user peer?
  • If no handshake: it’s NAT/firewall/endpoint reachability or key mismatch. Not “the NVR is down.”

Second: Is routing correct in both directions?

  • From hub, ip route get 10.10.50.20 should choose wg0.
  • Use tcpdump on wg0 while a user attempts access. If SYN leaves but no SYN-ACK returns: the site router/NVR path is broken on the return side.
  • Run traceroute -n from hub to NVR and see where it stops.

Third: Is firewall/policy blocking the right thing?

  • On hub: verify forward chain allows the required ports to the site subnet.
  • On site: verify camera VLAN firewall allows inbound from VPN subnet and allows return traffic.
  • Remember: “established,related” rules do not help if the initial SYN never reaches the destination.

Fourth: Is it performance (MTU, packet loss, saturation) rather than reachability?

  • Test MTU with DF ping sizes.
  • Check drops on wg0 and WAN interfaces.
  • Confirm how many concurrent streams and bitrates are being pulled.

Fifth: Application quirks (NVR UI, RTSP auth, ONVIF discovery)

  • HTTPS reachable doesn’t mean “login works.” Time skew and TLS settings can break UI.
  • RTSP may require TCP/UDP handling depending on client; some clients default to UDP and get blocked.
  • ONVIF discovery uses multicast/broadcast patterns that don’t traverse routed VPNs without helpers. Prefer direct IP connection for remote use.

Common mistakes: symptom → root cause → fix

These are the ones that show up repeatedly in real fleets, not in marketing diagrams.

1) “VPN connects, but cameras don’t load”

Symptom: User shows “connected” in VPN client; NVR web UI times out; ping may work.

Root cause: Hub routes exist, but forwarding firewall drops TCP 443/554; or site router blocks VPN subnet to camera VLAN.

Fix: Add explicit forward allow rules on the hub and site edge for required destination subnet + ports. Validate with nc -vz and tcpdump.

2) “It works from the hub server but not from laptops”

Symptom: Hub can reach NVR; remote client cannot.

Root cause: Client config lacks route to camera subnet (split tunnel not configured); AllowedIPs too narrow on client; or DNS points to public resolver.

Fix: Push/define AllowedIPs on the client to include the camera subnet(s). Ensure DNS is VPN-scoped and name resolves to private IP.

3) “Video stutters, UI is slow, but ping is fine”

Symptom: Login works; one stream works; multiple streams stutter or freeze.

Root cause: Hub CPU limits, WAN uplink saturation at site, or MTU fragmentation/blackholing under load.

Fix: Reduce stream bitrate/resolution for remote profiles; enable substreams; adjust MTU; scale hub instance; avoid full-tunneling all traffic.

4) “Everything breaks when the ISP changes at the site”

Symptom: Site goes dark after ISP swap; no handshake.

Root cause: Site peer can’t reach hub due to upstream firewall/NAT policy; old rules whitelisted hub port; or the site used a brittle “port open” assumption.

Fix: Ensure outbound UDP to hub port (e.g., 51820) is allowed. Use PersistentKeepalive for NAT. Document ISP requirements.

5) “Two sites can’t be online at the same time”

Symptom: Bringing up Site B causes Site A routes to vanish or traffic to flip-flop.

Root cause: Overlapping subnets (both sites use 192.168.1.0/24, etc.) or AllowedIPs overlapping on the hub.

Fix: Stop using overlapping addressing for routed access. If renumbering is impossible, use NAT at the site edge (carefully) or deploy per-site VRFs—both are work, pick your pain knowingly.

6) “ONVIF discovery works in the office but not over VPN”

Symptom: Camera discovery tool finds nothing remotely; direct IP works.

Root cause: ONVIF discovery uses multicast/broadcast patterns not carried over routed VPN by default.

Fix: Use direct IP/host lists for remote access. If discovery is mandatory, deploy a discovery proxy at the site or use NVR-centric management.

7) “Random users can reach cameras they shouldn’t”

Symptom: A user with VPN access can scan camera VLANs across multiple sites.

Root cause: Flat VPN policy; hub forward chain allows broad destination ranges; no per-group rules.

Fix: Segment VPN address pools by role; enforce destination restrictions at the hub; consider per-site jump hosts or an identity proxy for UI.

Three corporate mini-stories from the trenches

Mini-story 1: The incident caused by a wrong assumption

A company with a handful of warehouses rolled out a “simple” solution: every site router established a tunnel to the main office, and the SOC could view cameras. It worked. For months. Everyone relaxed, which is how failure becomes a surprise.

Then one warehouse got a new ISP. The site still had “internet,” so local camera recording was fine. But remote access died. Facilities reported “VPN down,” IT responded “ISP issue,” and Security escalated because they needed footage for an investigation.

The wrong assumption: “Outbound internet means outbound UDP on our chosen port.” The new ISP-provided modem did “helpful security” by blocking outbound UDP except common ports, and nobody noticed during install. The tunnel never handshook again.

They burned half a day arguing about who owned it. The fix took ten minutes: move WireGuard to a permitted port and explicitly allow outbound UDP from the site router. The real fix took longer: update the deployment checklist to include “validate UDP egress to hub,” and require a post-cutover handshake check as a sign-off gate.

Mini-story 2: The optimization that backfired

A different org decided their hub VM was “overprovisioned.” They downsized it to save money, because the VPN “is just routing.” Someone looked at average throughput graphs and declared victory.

Two weeks later, during a regional incident, multiple managers pulled up live views simultaneously. The hub CPU pinned, packets dropped, and users experienced “camera flapping.” It looked like a camera problem, then a site uplink problem, then an NVR problem—because humans love blaming the edge.

What actually happened: encryption overhead + conntrack + logging + a burst of concurrent streams pushed the smaller instance over its comfortable limit. Average usage was irrelevant; the workload had sharp peaks. CCTV is spiky by nature—people don’t watch 24/7, they stampede during incidents.

The backfire wasn’t the downsizing itself; it was the lack of load testing and the absence of a clear SLO (“X concurrent streams at Y bitrate with Z latency”). They reverted the instance size, rate-limited non-essential streams, and added a “low bandwidth profile” for remote users. Then they kept it that way, because spending a little on headroom is cheaper than an incident bridge at 2 a.m.

Mini-story 3: The boring but correct practice that saved the day

One enterprise had a dull practice: every CCTV site had a standard addressing scheme (no overlaps), every site tunnel had a documented camera subnet, and every change required a quick validation script run from the hub.

During a storm, several sites lost power and came back. A subset of site routers rebooted into a degraded state: WAN was up, but the interface for the camera VLAN didn’t come back cleanly because of a switch negotiation quirk. Locally, staff could still see some camera feeds because of caching and partial connectivity. Remotely, it looked like “VPN but no cameras.”

The on-call didn’t guess. They ran the same checks: handshake OK, route OK, TCP SYN leaves, no SYN-ACK. That immediately put the issue on the site side, not on the hub. They called the field tech with an exact instruction: bounce the switch port and verify the VLAN interface is up. No wandering.

Because the environment was standardized, they fixed multiple sites quickly. The “boring” part—consistent subnets, consistent routing, consistent checks—meant the outage didn’t turn into an interpretive dance of tribal knowledge.

Checklists / step-by-step plan

If you do this as an “IT project,” it will sprawl. Do it as an operational rollout with clear gates.

Step 1: Inventory and traffic expectations

  • List each site’s camera VLAN/subnet and NVR IP(s).
  • Document which ports are required: HTTPS, RTSP, vendor SDK ports, time sync.
  • Estimate concurrent remote viewers and expected bitrate (main stream vs substream).
  • Decide whether you require access to cameras directly, or just to NVR UI. Prefer NVR UI for remote users; it centralizes auth and limits lateral movement.

Step 2: Pick your hub placement and failure model

  • Office hub is fine if office internet is resilient and monitored.
  • Cloud hub is fine if you can operate it like production (patching, backups, IaC, monitoring).
  • Decide whether you need one hub or two for redundancy. If camera access is mission-critical, a single hub is a single excuse.

Step 3: Addressing plan that won’t sabotage you later

  • Allocate a dedicated VPN subnet (e.g., 10.44.0.0/24).
  • Ensure each site’s camera subnet is unique across the fleet. If you already have overlaps, prioritize renumbering or isolate via NAT/VRF with clear documentation.
  • Reserve IP blocks for user roles if you’ll enforce policy by source IP (e.g., 10.44.0.100/26 for operators, 10.44.0.200/27 for admins).

Step 4: Build the hub with restrictive defaults

  • Enable WireGuard, IP forwarding, and strict firewall policy (default drop forward).
  • Log denies (with rate limiting) so you can debug without drowning.
  • Set up DNS for VPN clients (split DNS) if you want friendly names.
  • Decide how you distribute configs and rotate keys. Manual configs do not scale past “a few people and one on-call.”

Step 5: Onboard one pilot site end-to-end

  • Bring up the site tunnel and confirm handshake stability (include PersistentKeepalive if NATed).
  • Verify hub-to-NVR reachability and port checks.
  • Verify remote client-to-NVR reachability and port checks.
  • Measure a real stream and note CPU and bandwidth impact on hub and site WAN.

Step 6: Roll out policies, not just connectivity

  • Implement per-site destination rules: users who don’t need Site A shouldn’t reach it.
  • Implement role rules: viewers vs administrators.
  • Block lateral movement: prevent VPN client subnets from talking to each other unless explicitly required.

Step 7: Operationalize

  • Monitoring: handshake age, hub CPU, interface drops, throughput, basic TCP checks to critical NVRs.
  • Alerting: “site tunnel down,” “hub overloaded,” “packet drops increasing.”
  • Runbooks: include the fast diagnosis playbook and the exact commands you’ll run.
  • Change control: a small config tweak can route half your network into a black hole.

FAQ

1) Do I really need a VPN? Can’t I just use the vendor’s P2P cloud?

You can, but you’re outsourcing your perimeter and your audit trail. If you have compliance requirements, or if you want to control who can access what, a VPN (or identity proxy) is the safer operational default.

2) What if the site has no public IP and is behind CGNAT?

That’s fine for hub-and-spoke as long as the site can make outbound connections to the hub. WireGuard works well here; use PersistentKeepalive so NAT mappings don’t expire.

3) Should I use IPsec instead of WireGuard?

Use what your team can operate reliably. IPsec is ubiquitous and often baked into firewalls; it’s also easier to misconfigure and harder to debug. WireGuard is simpler and tends to be more predictable. If your edge gear already has well-supported IPsec and you have people who know it, IPsec is perfectly valid.

4) Can I access cameras directly over VPN, or only the NVR?

Prefer NVR for remote viewing: fewer endpoints exposed, centralized auth, and less chance of someone poking random camera web UIs. Direct camera access is sometimes needed for commissioning or diagnostics; gate it behind admin-only policy.

5) Why does ONVIF discovery fail over VPN?

Discovery commonly relies on multicast/broadcast behavior that doesn’t cross routed networks by default. VPNs are usually routed. Solution: connect by IP/host list, or deploy on-site tooling that does discovery locally.

6) Do I need split tunneling?

Usually yes. Split tunnel only the camera/NVR subnets through the VPN. Full-tunneling all traffic makes your hub a choke point for unrelated browsing and can wreck performance during video events.

7) How do I prevent one site from reaching another site’s cameras?

On the hub, enforce forwarding policy that allows VPN clients to reach only specific destination subnets. Also keep AllowedIPs tight per peer. Assume “if it can route, someone will eventually scan it.”

8) What’s the minimum logging I should have?

At minimum: connection events (peer handshakes or session establishment), firewall allow/deny logs (rate-limited), and a mapping of VPN identity (key/user) to access policy. Without that, your incident response becomes interpretive art.

9) Can I put the hub in the cloud if cameras are on private LANs?

Yes. Sites initiate outbound tunnels to the cloud hub; users connect to the hub; routes are exchanged at the hub. The cloud hub becomes your meeting point. Treat it like production infrastructure: patch it, monitor it, and back up configs.

10) How do I handle overlapping camera subnets across sites?

Renumber if you can. If you can’t, use NAT at the site edge (translate each site into a unique “virtual” subnet) or isolate with VRFs. NAT adds complexity and can break some discovery protocols, but it’s sometimes the least-bad retrofit.

Conclusion: next steps you can do this week

If you want secure CCTV access without public IPs, stop negotiating with physics and start controlling your topology.

  1. Pick a reference design: hub-and-spoke is the practical default for multi-site CCTV.
  2. Standardize addressing: unique camera subnets per site, dedicated VPN subnet, documented ports.
  3. Implement WireGuard (or IPsec) with strict policy: default drop, allow only required ports, block lateral movement.
  4. Operationalize from day one: handshake monitoring, route checks, port checks, and a short runbook that an on-call can follow at 3 a.m.
  5. Pilot one site, measure bandwidth and hub CPU, then roll out with a checklist and sign-off gates.

Do the boring thing. Future-you will be delighted, which is rare in infrastructure.

← Previous
Vaporware in Production: How Press-Release Products Break Real Systems
Next →
Proxmox Failed After Update: Roll Back Kernel, Fix Boot, and Recover a Broken Node Safely

Leave a comment