Notes: CCTV

A quick overview of my current CCTV setup.

Cameras

I use relatively cheap cameras from Amazon, so long as they support RTSP protocol thats my only hard requirement, they also all support IR (night mode), and are at least 1080p quality.

The Cameras are all wireless and unfortunately I have to use their branded app to set them up and configure their general settings, but once thats done and i've made sure RTSP is turned on i've not had to use the branded app at all.

Each camera has an SD card for local recording, I just do this as a backup in case RTSP stops working or it has any hiccups but generally they're old SD cards I had lying around so will only record a day or so's footage.

I also make a note of each cameras username and password to access its RTSP feed.

Wifi wise they are all connected to a dedicated wifi access point, this is so my main home wifi isn't congested with camera footage constantly streaming. The access point is an old wifi extender that i'd since upgraded so only runs via 2.4ghz.

CCTV PC

The CCTV PC is an old machine of mine, using an Intel i5 Skylake from quite a few years ago. Luckily thanks to Intel it has Quick Sync Encoding which makes it faster at transcoding video on the fly.

OS wise it currently runs Linux Mint, but Ubuntu, Debian or any other Linux based OS would also work fine. I'm running a desktop based OS purely because I have a spare monitor hooked up, but generally I manage everything remotely via SSH or within the NVR software.

I use Frigate as my NVR (Network Video Recorder) software running via Docker Compose. But there's plenty of other ways to install it.

I access the machine remotely via Tailscale, which I use as my mesh VPN. It lets me treat all machines within my Tailnet like a local private network, I point my devices browser to the IP Tailscale assigns to my NVR machine along with the port number Frigate uses for the web interface and I have access to my camera footage. I can even "Add to homescreen" on my phone to "install it as an app".

I made sure after adding the machine to Tailscale to disable key expiry, this means I won't have to manually re-authenticate the machine with Tailsacle after setting it up. This could be considered risky, but for me its worth the tradeoff.

The Firewall (UFW) is setup to only allow SSH and the ports required for Frigate via the tailscale0 network device, meaning I have to be authenticated on the Tailscale VPN to access the machine remotely. If anything goes wrong I can always just physically walk up to the machine so long as i'm at home and fix whatever is the issue with the VPN.

SSH is setup to only allow key based authentication and root access is disabled via SSH.

Unattended-upgrades is installed to ensure security updates are automatically installed without manual input.

Configuring Frigate

Step 1 - Docker Compose configuration

Make sure to install the official docker package which gives you access to the docker compose command (not docker-compose).

frigate:
container_name: frigate
privileged: true # this may not be necessary for all setups
restart: unless-stopped
image: ghcr.io/blakeblackshear/frigate:stable
shm_size: "500mb" # update for your cameras based on calculation above
devices:
    - /dev/dri/renderD128:/dev/dri/renderD128 # For Intel Quick Sync, needs to be updated for your hardware
volumes:
    - /etc/localtime:/etc/localtime:ro
    - PATH_TO_FRIGATE_CONFIG_FILE:/config
    - PATH_TO_EXTERNAL_DRIVE:/media/frigate
    - type: tmpfs # Optional: 1GB of memory, reduces SSD/SD Card wear
    target: /tmp/cache
    tmpfs:
        size: 1000000000
ports:
    - "5000:5000"
    - "8554:8554" # RTSP feeds
    - "8555:8555/tcp" # WebRTC over tcp
    - "8555:8555/udp" # WebRTC over udp
environment:
    FRIGATE_RTSP_PASSWORD: "A_STRONG_PASSWORD"

Step 2 - Frigate config file

In Frigate, go to config editor and add something like the following:

mqtt:
  enabled: false # <------ I don't use this feature (aka subscribing to events)

cameras:
  drive: # <------ Name the camera
    enabled: true
    ffmpeg:
      inputs:
        - path: rtsp://USERNAME:PASSWORD@YOUR_CAMERA_IP_ADDRESS:554 # <----- The stream you want to use
          roles:
            - detect
            - record
      hwaccel_args: preset-vaapi # <---- enable Intel Quick Sync encoding
    record:
      retain:
        days: 3
        mode: all
    detect:
      enabled: true # <---- disable detection until you have a working camera feed

go2rtc: # <---- Allows for realtime viewing
  streams:
    drive: # <------ Match the camera name
      - rtsp://USERNAME:PASSWORD@YOUR_CAMS_IP_ADDRESS:554 # <------ Match the RTSP feed

record: # <------ My general settings for recording
  enabled: true
  retain:
    mode: motion
    days: 3
  alerts:
    retain:
      days: 30
    pre_capture: 5
    post_capture: 8
  detections:
    retain:
      days: 30
    pre_capture: 5
    post_capture: 8
snapshots:
  enabled: true
  retain:
    default: 30
version: 0.15-1

Once both of these are setup run docker compose up -d which should run the docker setup in the background.