By Self Hosted frigate docker cloudflare mqtt mosquitto home-lab

Self-Hosted Frigate with App Notifications and Remote Access via Cloudflare

Self-host Frigate with ViewU notifications, Mosquitto MQTT, and secure remote access through Cloudflare Tunnel and Access. No router port forwarding required.

Self-hosted Frigate setup with Cloudflare Tunnel, Mosquitto MQTT, and ViewU notifications
This setup runs Frigate, ViewU, Mosquitto, and Cloudflare Tunnel with Docker Compose.
The goal is simple: keep Frigate and camera recordings self-hosted, get mobile notifications through ViewU, and securely access live cameras, events, and recordings while away from home.
Nothing needs to be port-forwarded through the router. MQTT and MQTT over WebSockets stay inside the Docker network, while Cloudflare Tunnel handles remote access to Frigate.
1. Create the directories
Keep persistent Frigate and Mosquitto data under /srv:
sudo mkdir -p /srv/frigate/config
sudo mkdir -p /srv/frigate/media
sudo mkdir -p /srv/mosquitto/{config,data,log}

sudo chown -R $USER:$USER /srv/frigate /srv/mosquitto

Then create a directory for the Docker Compose stack:
mkdir -p ~/frigate-stack
cd ~/frigate-stack

The final layout will look roughly like this:
/srv/
├── frigate/
│   ├── config/
│   └── media/
└── mosquitto/
    ├── config/
    │   ├── mosquitto.conf
    │   └── passwd
    ├── data/
    └── log/

~/frigate-stack/
├── compose.yml
└── .env

2. Configure Mosquitto
Create the Mosquitto configuration:
nano /srv/mosquitto/config/mosquitto.conf

Add:
persistence true
persistence_location /mosquitto/data/

log_dest stdout

listener 1883
protocol mqtt

listener 9001
protocol websockets

allow_anonymous false
password_file /mosquitto/config/passwd

We are keeping both listeners.
Port 1883 is standard MQTT and is used for normal MQTT traffic between Frigate, Mosquitto, and ViewU.
Port 9001 provides MQTT over WebSockets, which is also required for this setup.
Neither listener needs to be published directly to the internet. Containers on the same Docker network can reach them as:
mosquitto:1883
mosquitto:9001

This keeps the MQTT side of the stack private while still making both protocols available to the services that need them.
3. Create the MQTT user and password
Use the Mosquitto image to create the password file:
docker run --rm -it \
  -v /srv/mosquitto/config:/mosquitto/config \
  eclipse-mosquitto:2 \
  mosquitto_passwd -c /mosquitto/config/passwd viewu

Enter a strong password when prompted.
This creates:
/srv/mosquitto/config/passwd

Mosquitto will use this file to authenticate clients connecting over both MQTT and WebSockets.
If you need another MQTT user later:
docker run --rm -it \
  -v /srv/mosquitto/config:/mosquitto/config \
  eclipse-mosquitto:2 \
  mosquitto_passwd /mosquitto/config/passwd another-user

4. Create the .env file
Move into the Compose directory:
cd ~/frigate-stack
nano .env

Add:
MQTT_USER=viewu
MQTT_PASSWORD=CHANGE_ME
CLOUDFLARE_TUNNEL_TOKEN=CHANGE_ME

MQTT_PASSWORD should match the password you created with mosquitto_passwd.
We will add the Cloudflare Tunnel token shortly.
Lock down the file:
chmod 600 .env


5. Create the Docker Compose stack
Create:
nano compose.yml

Add:
services:

  mosquitto:
    image: eclipse-mosquitto:2
    container_name: mosquitto
    restart: unless-stopped

    command: /usr/sbin/mosquitto -c /mosquitto/config/mosquitto.conf

    volumes:
      - /srv/mosquitto/config:/mosquitto/config
      - /srv/mosquitto/data:/mosquitto/data
      - /srv/mosquitto/log:/mosquitto/log

    networks:
      - frigate-net


  frigate:
    image: ghcr.io/blakeblackshear/frigate:stable
    container_name: frigate
    restart: unless-stopped

    privileged: true
    stop_grace_period: 30s
    shm_size: "256mb"

    ports:
      - "127.0.0.1:15000:5000"

    volumes:
      - /srv/frigate/config:/config
      - /srv/frigate/media:/media/frigate

    tmpfs:
      - /tmp/cache:size=1000000000

    depends_on:
      - mosquitto

    networks:
      - frigate-net


  viewu:
    image: mjeoffline/viewu:amd64_3.5
    container_name: viewu
    restart: unless-stopped

    environment:
      MQTT_IP: "mosquitto"
      MQTT_PORT: "1883"
      MQTT_USER: "${MQTT_USER}"
      MQTT_PASSWORD: "${MQTT_PASSWORD}"

    depends_on:
      - mosquitto

    networks:
      - frigate-net


  cloudflared:
    image: cloudflare/cloudflared:latest
    container_name: cloudflared
    restart: unless-stopped

    command: tunnel --no-autoupdate run --token ${CLOUDFLARE_TUNNEL_TOKEN}

    depends_on:
      - frigate

    networks:
      - frigate-net


networks:
  frigate-net:
    driver: bridge

A few important configuration choices
Both MQTT protocols stay available.
Mosquitto listens internally on:
1883 - MQTT
9001 - MQTT over WebSockets

There is no ports: section on the Mosquitto container because Docker containers on frigate-net can reach both listeners directly.
If you later have a client outside Docker that genuinely needs direct WebSocket access, you can publish 9001 separately. For this stack, there is no reason to expose Mosquitto directly to the internet.
ViewU uses standard MQTT on port 1883.
The container connects to:
mosquitto:1883

The WebSocket listener on 9001 remains available for the parts of the setup that require MQTT over WebSockets.
Frigate only listens locally on the Docker host.
ports:
  - "127.0.0.1:15000:5000"

That gives us a local troubleshooting endpoint at:
http://127.0.0.1:15000

without exposing Frigate across the LAN.
Cloudflare talks directly to Frigate.
Because cloudflared is on the same Docker network, it can reach:
http://frigate:5000

There is no need for Cloudflare to go through the host's 15000 port.
Secrets live in .env.
The MQTT credentials and Cloudflare Tunnel token are not hardcoded into compose.yml.
Using port 15000 instead of 5000 is not a security feature by itself. Binding the service to 127.0.0.1 and avoiding unnecessary exposed services is what matters.
6. Configure MQTT in Frigate
Frigate also needs to know about the MQTT broker.
In your Frigate configuration, add:
mqtt:
  host: mosquitto
  port: 1883
  user: viewu
  password: YOUR_MQTT_PASSWORD

Docker's internal DNS resolves mosquitto to the Mosquitto container.
Use the same username and password created earlier.
Frigate will publish its events over MQTT on port 1883, while Mosquitto also keeps the 9001 WebSocket listener available.
Your camera, detector, recording, snapshot, and object detection settings can then be configured normally in Frigate.
7. Create the Cloudflare Tunnel
Now we need a secure way to reach Frigate when we are away from home.
Open the Cloudflare Zero Trust dashboard and create a new Cloudflare Tunnel.
The flow is roughly:
Networks → Tunnels → Create Tunnel → Cloudflared

Give the tunnel a simple name such as:
frigate

Choose Docker as the environment.
Cloudflare will generate a command containing a long tunnel token.
Copy the token into:
nano ~/frigate-stack/.env

Update:
CLOUDFLARE_TUNNEL_TOKEN=your-long-cloudflare-token

Treat this token like a password. Anyone with it could potentially run another connector for your tunnel.
8. Add a hostname for Frigate
In the Cloudflare Tunnel configuration, create a public hostname such as:
frigate.example.com

Point it to:
http://frigate:5000

This works because cloudflared and Frigate share the same Docker network.
Traffic now looks like this:
Phone / Laptop
      │
      ▼
   Internet
      │
      ▼
  Cloudflare
      │
      ▼
Cloudflare Tunnel
      │
      ▼
frigate:5000

There is no need to open 15000, 5000, 1883, or 9001 on your router.
9. Add Cloudflare Access
The tunnel gets traffic back to Frigate, but I also want an authentication layer before anyone reaches the Frigate UI.
Create a Cloudflare Access application for:
frigate.example.com

Keep the policy simple at a high level:
  • Allow only approved users or email addresses.
  • Require authentication.
  • Enable MFA where available.
  • Deny everyone else.
How you configure the identity provider and exact policies is up to you.
The important distinction is:
Cloudflare Tunnel provides the connection back home. Cloudflare Access controls who is allowed through it.
10. Start everything
Back in the Compose directory:
cd ~/frigate-stack

Validate the Compose file:
docker compose config

Pull the images:
docker compose pull

Start the stack:
docker compose up -d

Check the containers:
docker compose ps

You should see:
frigate
mosquitto
viewu
cloudflared

11. Check the logs
If something is not working, start with the container logs.
Mosquitto:
docker compose logs --tail=100 mosquitto

Frigate:
docker compose logs --tail=100 frigate

ViewU:
docker compose logs --tail=100 viewu

Cloudflare:
docker compose logs --tail=100 cloudflared

Or follow everything together:
docker compose logs -f

For Mosquitto, you should see both listeners starting successfully:
1883 - MQTT
9001 - WebSockets

If the WebSocket listener fails, fix that before moving on.
12. Set up ViewU notifications
ViewU connects to the same Mosquitto broker as Frigate:
Frigate
   │
   │ MQTT events
   ▼
Mosquitto
   │
   ├── 1883 MQTT
   │
   └── 9001 WebSockets
   │
   ▼
 ViewU
   │
   ▼
Phone notifications

The Docker environment points ViewU at:
mosquitto:1883

with the MQTT username and password coming from .env.
Mosquitto also keeps its WebSocket listener available at:
mosquitto:9001

Once Frigate starts publishing detection events, ViewU can use those events for mobile notifications.
Finish the app-side ViewU configuration and trigger a test event to make sure notifications are arriving.
13. Test remote access
First, make sure Frigate works locally on the server:
http://127.0.0.1:15000

Then test the Cloudflare hostname:
https://frigate.example.com

For a proper test, turn Wi-Fi off on your phone and use mobile data.
You should hit Cloudflare Access first.
After authentication, you should be able to open Frigate and access:
  • Live camera feeds
  • Detection events
  • Recordings
  • Clips
  • Snapshots and other media
Then trigger a detection event and confirm that the ViewU notification arrives on your phone.
Final setup
The finished setup looks roughly like this:
                         Internet
                            │
                    Cloudflare Access
                            │
                    Cloudflare Tunnel
                            │
                            ▼
                         Frigate
                  Live / Events / Media
                            │
                     Docker Network
                            │
                  ┌─────────┴─────────┐
                  │                   │
                  ▼                   ▼
              Mosquitto              ViewU
             1883 MQTT                │
          9001 WebSockets             │
                  ▲                   ▼
                  └──── Frigate ──► Phone
                        events     notifications

Frigate and the recordings stay on your own server. Mosquitto provides both normal MQTT on 1883 and MQTT over WebSockets on 9001. ViewU handles the mobile notification side, and Cloudflare gives you a secure route back to Frigate when you are away from home.
The part I like about this setup is that there is no direct internet exposure and no router port forwarding.
You still get live remote access, recordings and event history, MQTT and WebSocket support, plus notifications on your phone without turning Frigate or Mosquitto into publicly exposed services.

Comments (0)

No comments yet.

Leave a comment

Comments are reviewed before they're published — yours will appear here once approved.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.