Show HN: CheapSecurity – Lightweight, Self-Hosted CCTV for Linux SBCs
Summary
CheapSecurity is a lightweight, self-hosted CCTV solution for Linux single-board computers, offering privacy-focused home monitoring with motion detection, recording, and Telegram alerts, all without cloud subscriptions.
View Cached Full Text
Cached at: 07/27/26, 01:41 AM
gmrandazzo/CheapSecurity
Source: https://github.com/gmrandazzo/CheapSecurity
CheapSecurity
This project provides a lightweight, self-hosted CCTV solution designed for Linux-based single-board computers (SBCs) and standard USB webcams. It offers an affordable, privacy-focused alternative for home monitoring by keeping your video data entirely under your control. Project Philosophy
- Privacy-First: By storing all footage locally, this system eliminates the need for third-party cloud subscriptions and ensures your data never leaves your network.
- Cost-Effective: Leverage existing hardware—such as a spare Linux board and a USB webcam—to build a fully functional surveillance system without recurring fees.
- Minimalist Architecture: The software is optimized to run efficiently on low-power devices, ensuring high performance even on entry-level hardware.
Key Features
- Hardware Agnostic: Highly compatible with a wide range of standard USB webcams.
- Resource Efficient: Optimized specifically for Linux-based boards (e.g., Raspberry Pi, Orange Pi, or similar SBCs).
- Data Sovereignty: Full control over your storage path, retention policies, and access methods.
- Simple Deployment: Designed for quick setup and easy maintenance.
Features
- Live MJPEG stream with a web dashboard
- Motion detection with frame differencing
- Automatic recording with a pre-motion buffer
- Email alerts with a snapshot picture when motion starts
- Telegram integration:
- Automatic video upload after motion is recorded
- Bot commands:
/snapshot,/video <seconds>,/help
- Night mode low-light enhancement (software CLAHE + brightness/contrast boost)
- Recordings bulk actions: select all, send to Telegram, download ZIP, delete
- Storage cleanup by age, total size, and emergency low-disk cleanup
- systemd autostart ready
- Licensed under GNU AGPLv3
Requirements
- Python 3.10 or newer
- OpenCV with V4L2 support (see installation options below)
- A USB webcam (
/dev/video0by default) - Optional: a Telegram bot token for Telegram notifications
- Optional: SMTP credentials for email alerts
Quick start
-
Verify OpenCV is available:
python3 -c "import cv2; print(cv2.__version__)"If OpenCV is not installed, you have two options:
- Option A — use a system OpenCV package (recommended on ARM boards such as the Odroid XU4, where a pre-built system package is usually optimized for the board).
- Option B — install OpenCV via pip (convenient on x86/amd64 machines or when no system package is available). Use
opencv-python-headlessbecause the app does not need a GUI.
-
Create and activate the virtual environment and install the app:
Option A: system OpenCV (recommended for ARM)
This creates a venv that can see the system site-packages, so the system
cv2is available inside the venv.cd $HOME/CheapSecurity python3 -m venv venv --system-site-packages source venv/bin/activate pip install -e .Option B: install everything via pip
Use this if you do not have a system OpenCV or prefer a self-contained venv.
cd $HOME/CheapSecurity python3 -m venv venv source venv/bin/activate pip install opencv-python-headless pip install -e .Note: On some older ARM boards the pip
opencv-python-headlesswheel may not be available or may be slow. If that happens, install OpenCV from your distribution’s package manager instead and use Option A. -
Find your webcam device (usually
/dev/video0):v4l2-ctl --list-devices -
Copy
config.json.exampletoconfig.jsonand edit it:cp config.json.example config.json nano config.json- Set camera device, resolution, and frame rate
- Fill in SMTP credentials if you want email alerts
- Fill in Telegram bot token and chat ID if you want Telegram uploads
Security:
config.jsonis listed in.gitignoreand must never be committed. It contains passwords and tokens. Always editconfig.json, notconfig.json.example. If you add a new setting, update both files so the example stays in sync. -
Run the app:
./venv/bin/python -m cheapsecurity.app -
Open the dashboard in a browser:
http://<odroid-ip>:5000
Configuration
Edit config.json:
| Section | Key | Description |
|---|---|---|
camera | device | V4L2 device index (0 = /dev/video0) |
camera | width, height, fps | Capture resolution and frame rate |
camera | night_mode | Enable low-light enhancement |
camera | night_mode_fps | Target FPS in night mode (camera may ignore this) |
camera | night_mode_gain | Target analog gain in night mode (camera may ignore this) |
camera | night_mode_brightness | Brightness boost in night mode |
camera | night_mode_contrast | Contrast boost in night mode |
motion | threshold | Pixel difference threshold (0-255) |
motion | min_area | Minimum contour area to trigger motion (full-res pixels) |
motion | cooldown_seconds | Keep recording after motion stops |
motion | scale | Downscale factor for motion detection (saves CPU) |
recording | dir | Where videos are saved |
recording | max_duration_seconds | Maximum length of one clip |
recording | pre_buffer_seconds | Seconds before motion included in clip |
recording | codec | Preferred FourCC codec (MJPG for low CPU, mp4v for smaller files) |
notifications | enabled | Send email alerts on motion |
notifications | smtp | SMTP server, port, username, password, TLS |
notifications | from, to, subject | Email sender/recipients/subject (use ["a@...", "b@..."] for multiple recipients) |
notifications | min_interval_minutes | Minimum time between alert emails |
telegram | enabled | Send videos to Telegram after motion is recorded |
telegram | bot_token, chat_id | Telegram Bot API token and destination chat |
telegram | send_video | Whether to upload the video file automatically |
telegram | min_interval_minutes | Minimum time between Telegram uploads |
telegram | poll_commands | Enable /snapshot, /video, and /help bot commands |
storage | max_age_days | Delete recordings older than this (default 3 days = 72h) |
storage | max_size_gb | Delete oldest files if total exceeds this |
storage | cleanup_interval_minutes | How often storage cleanup runs |
storage | delete_old_on_startup | If false, old recordings are kept when the app restarts |
storage | emergency_free_space_gb | If free disk space drops below this, delete old recordings before a new one |
storage | emergency_delete_count | How many oldest recordings to delete in an emergency cleanup |
web | host, port | Dashboard bind address and port |
web | stream_scale | Downscale factor for live stream (saves bandwidth/CPU) |
web.auth | enabled, username, password | Optional HTTP Basic Auth |
Telegram setup
1. Create a bot
- Open Telegram and message @BotFather.
- Send
/newbotand follow the prompts to choose a display name and username. - Copy the bot token (looks like
123456789:ABCdefGHIjklMNOpqrsTUVwxyz). - Keep this token secret — anyone with it can control your bot.
2. Get your chat ID
- Start a private chat with your new bot and send any message (for example,
/start). - Open this URL in a browser, replacing
<YOUR_BOT_TOKEN>with the real token:https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates - Look for
"chat":{"id":123456789. The number is your chat ID.- If
getUpdatesis empty, send another message to the bot and refresh. - If you want to use a group chat, add the bot to the group first and send a message there; the chat ID will be negative for groups.
- If
- Copy the chat ID exactly, including the
-sign if it is a group.
3. Configure the app
Fill in the telegram section of config.json:
"telegram": {
"enabled": true,
"bot_token": "123456789:ABCdefGHIjklMNOpqrsTUVwxyz",
"chat_id": "123456789",
"send_video": true,
"min_interval_minutes": 5,
"poll_commands": true
}
Then restart the service:
sudo systemctl restart cheapsecurity@$(whoami).service
Automatic uploads
After a motion clip is saved, the video is uploaded to your Telegram chat. Uploads are rate-limited by min_interval_minutes.
Bot commands
From your configured chat, send:
/snapshot— receive the current camera picture/video 10— record and send a 10-second video (1–60 seconds, default 10)/help— list commands
The bot only responds to your configured chat_id.
Motion has priority: if the system is already recording because motion was detected, a /video request will not interrupt it. The bot will reply that a motion video is in progress and will be uploaded automatically.
Email alerts
Configure the notifications section in config.json. A picture from the moment motion starts is attached. Alerts are rate-limited by min_interval_minutes.
Gmail / Google Workspace setup
Google no longer allows “less secure apps” to use your regular Gmail password. You must create an App Password.
- Enable 2-Step Verification on your Google account:
- https://myaccount.google.com/signinoptions/two-step-verification
- Create an App Password:
- Go to https://myaccount.google.com/apppasswords
- Select app: Mail
- Select device: Other (Custom name) — type “CheapSecurity”
- Click Generate and copy the 16-character password (for example,
abcd efgh ijkl mnop).
- In
config.json, set:"notifications": { "enabled": true, "smtp": { "server": "smtp.gmail.com", "port": 465, "username": "[email protected]", "password": "abcdefghijklmnop", "use_tls": true }, "from": "[email protected]", "to": "[email protected]", "subject": "CheapSecurity motion alert", "min_interval_minutes": 5 }- Use the App Password (no spaces) in the
passwordfield, not your Google account password. - For Google Workspace accounts, the username is usually your full email address.
- The app uses implicit TLS (
SMTP_SSL) on the port you configure. Gmail accepts this on port 465.
- Use the App Password (no spaces) in the
Multiple recipients
"to": [
"[email protected]",
"[email protected]"
]
Night mode
Night mode combines:
- Software enhancement (CLAHE on the L channel)
- Camera brightness/contrast boost
- Attempts to lower FPS and raise gain/ISO if the camera supports it
Toggle it from the dashboard. It is applied to the live stream, recordings, and alert pictures.
Important: most USB webcams do not expose ISO/gain/exposure controls via V4L2, so FPS/gain adjustments may be ignored. True night vision requires an IR-sensitive camera and an IR illuminator.
Storage and cleanup
- Recordings are saved in
recordings/. - Recordings older than
max_age_daysare deleted during periodic cleanup, not on startup (unlessdelete_old_on_startupistrue). - If free disk space drops below
emergency_free_space_gb, the oldestemergency_delete_countrecordings are deleted before starting a new clip. - Recordings older than
max_age_daysor exceedingmax_size_gbare removed during periodic cleanup.
Web interface
- Live stream
- Status panel (resolution, FPS, recording state, motion state)
- Settings toggles: night mode, email notifications, Telegram uploads, built-in basic auth
- Recordings list with per-row checkboxes and bulk actions:
- Select all
- Send to Telegram
- Download selected (ZIP)
- Delete selected
Production deployment
Do not expose Flask’s development server to the internet. Use Gunicorn behind the built-in auth or another reverse proxy you trust.
1. Install Gunicorn
It is already defined in pyproject.toml:
cd $HOME/CheapSecurity
source venv/bin/activate
pip install -e .
2. Run with systemd + Gunicorn
Copy the service template and enable it from a user shell:
sudo cp cheapsecurity.service /etc/systemd/system/[email protected]
sudo systemctl daemon-reload
sudo systemctl enable --now cheapsecurity@$(whoami).service
This binds Gunicorn to 0.0.0.0:5000 with one worker and four threads, so the dashboard and stream are reachable directly on your network. Only one worker is used because the camera must be opened by a single process.
Security: if you expose this to the internet, put a reverse proxy with HTTPS and authentication in front of Gunicorn. If you only access it locally, keep the built-in auth enabled.
View logs:
sudo journalctl -u cheapsecurity@$(whoami).service -f
Project structure
CheapSecurity/
├── src/
│ └── cheapsecurity/ # Python package
│ ├── app.py # Development launcher
│ ├── cctv.py # Motion detection, recording, alerts, Telegram bot
│ ├── web.py # Flask dashboard and APIs
│ ├── wsgi.py # Production WSGI entry point
│ ├── diagnose.py # Diagnostic/troubleshooting script
│ ├── templates/ # HTML templates
│ └── static/ # CSS/JS
├── tests/ # Test suite
├── config.json # Your local settings (gitignored, never commit)
├── config.json.example # Example settings template (committed)
├── pyproject.toml # Package metadata and dependencies
├── cheapsecurity.service # systemd template
├── LICENSE # GNU AGPLv3
└── recordings/ # Saved videos
Troubleshooting
If recordings stop appearing:
- Check the service is running:
sudo systemctl status cheapsecurity@$(whoami).service - Check logs:
sudo journalctl -u cheapsecurity@$(whoami).service -f - Run the diagnostic script:
source venv/bin/activate python -m cheapsecurity.diagnose - Try lowering
motion.min_areaif no motion is detected.
License
This project is licensed under the GNU Affero General Public License v3.0 or later (AGPLv3). See LICENSE.
Similar Articles
Show HN: Open-source private home security camera system (end-to-end encryption)
Secluso is an open-source, end-to-end encrypted home security camera system for Raspberry Pi that allows remote access without cloud surveillance. It features a 5-minute setup and reproducible builds.
The Best Subscription-Free Home Security Cameras I’ve Tried
Wired reviews the best subscription-free home security cameras that store footage locally, highlighting Eufy, Synology, TP-Link Tapo, and Aqara as top brands for privacy-conscious users.
Shelly’s new $50 security camera watches your home without a subscription
Shelly announced a new $50 security camera that can be used without a subscription, featuring local video recording and smart home automations, with optional cloud services.
The Best Motion Sensors and Home Security Gadgets Without Cameras
This article reviews motion sensors and home security gadgets that don't use cameras, offering privacy-focused alternatives for detecting activity.
The coolest anti-surveillance tools at Defcon [video]
At Def Con, independent hackers presented affordable, open-source tools for detecting surveillance technologies like smart cameras and fake cell towers, making counter-surveillance accessible to the public.