mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-01-29 07:24:56 +03:00
Add networking options for configuring listening ports (#21779)
This commit is contained in:
parent
5fdb56a106
commit
a2ae2903cf
3
Makefile
3
Makefile
@ -49,7 +49,8 @@ push: push-boards
|
|||||||
--push
|
--push
|
||||||
|
|
||||||
run: local
|
run: local
|
||||||
docker run --rm --publish=5000:5000 --volume=${PWD}/config:/config frigate:latest
|
docker run --rm --publish=5000:5000 --publish=8971:8971 \
|
||||||
|
--volume=${PWD}/config:/config frigate:latest
|
||||||
|
|
||||||
run_tests: local
|
run_tests: local
|
||||||
docker run --rm --workdir=/opt/frigate --entrypoint= frigate:latest \
|
docker run --rm --workdir=/opt/frigate --entrypoint= frigate:latest \
|
||||||
|
|||||||
@ -10,7 +10,8 @@ echo "[INFO] Starting certsync..."
|
|||||||
|
|
||||||
lefile="/etc/letsencrypt/live/frigate/fullchain.pem"
|
lefile="/etc/letsencrypt/live/frigate/fullchain.pem"
|
||||||
|
|
||||||
tls_enabled=`python3 /usr/local/nginx/get_listen_settings.py | jq -r .tls.enabled`
|
tls_enabled=`python3 /usr/local/nginx/get_nginx_settings.py | jq -r .tls.enabled`
|
||||||
|
listen_external_port=`python3 /usr/local/nginx/get_nginx_settings.py | jq -r .listen.external_port`
|
||||||
|
|
||||||
while true
|
while true
|
||||||
do
|
do
|
||||||
@ -34,7 +35,7 @@ do
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
liveprint=`echo | openssl s_client -showcerts -connect 127.0.0.1:8971 2>&1 | openssl x509 -fingerprint 2>&1 | grep -i fingerprint || echo 'failed'`
|
liveprint=`echo | openssl s_client -showcerts -connect 127.0.0.1:$listen_external_port 2>&1 | openssl x509 -fingerprint 2>&1 | grep -i fingerprint || echo 'failed'`
|
||||||
|
|
||||||
case "$liveprint" in
|
case "$liveprint" in
|
||||||
*Fingerprint*)
|
*Fingerprint*)
|
||||||
|
|||||||
@ -80,12 +80,12 @@ if [ ! \( -f "$letsencrypt_path/privkey.pem" -a -f "$letsencrypt_path/fullchain.
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# build templates for optional FRIGATE_BASE_PATH environment variable
|
# build templates for optional FRIGATE_BASE_PATH environment variable
|
||||||
python3 /usr/local/nginx/get_base_path.py | \
|
python3 /usr/local/nginx/get_nginx_settings.py | \
|
||||||
tempio -template /usr/local/nginx/templates/base_path.gotmpl \
|
tempio -template /usr/local/nginx/templates/base_path.gotmpl \
|
||||||
-out /usr/local/nginx/conf/base_path.conf
|
-out /usr/local/nginx/conf/base_path.conf
|
||||||
|
|
||||||
# build templates for optional TLS support
|
# build templates for additional network settings
|
||||||
python3 /usr/local/nginx/get_listen_settings.py | \
|
python3 /usr/local/nginx/get_nginx_settings.py | \
|
||||||
tempio -template /usr/local/nginx/templates/listen.gotmpl \
|
tempio -template /usr/local/nginx/templates/listen.gotmpl \
|
||||||
-out /usr/local/nginx/conf/listen.conf
|
-out /usr/local/nginx/conf/listen.conf
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
"""Prints the base path as json to stdout."""
|
|
||||||
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
base_path = os.environ.get("FRIGATE_BASE_PATH", "")
|
|
||||||
|
|
||||||
result: dict[str, Any] = {"base_path": base_path}
|
|
||||||
|
|
||||||
print(json.dumps(result))
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
"""Prints the tls config as json to stdout."""
|
|
||||||
|
|
||||||
import json
|
|
||||||
import sys
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from ruamel.yaml import YAML
|
|
||||||
|
|
||||||
sys.path.insert(0, "/opt/frigate")
|
|
||||||
from frigate.util.config import find_config_file
|
|
||||||
|
|
||||||
sys.path.remove("/opt/frigate")
|
|
||||||
|
|
||||||
yaml = YAML()
|
|
||||||
|
|
||||||
config_file = find_config_file()
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(config_file) as f:
|
|
||||||
raw_config = f.read()
|
|
||||||
|
|
||||||
if config_file.endswith((".yaml", ".yml")):
|
|
||||||
config: dict[str, Any] = yaml.load(raw_config)
|
|
||||||
elif config_file.endswith(".json"):
|
|
||||||
config: dict[str, Any] = json.loads(raw_config)
|
|
||||||
except FileNotFoundError:
|
|
||||||
config: dict[str, Any] = {}
|
|
||||||
|
|
||||||
tls_config: dict[str, any] = config.get("tls", {"enabled": True})
|
|
||||||
networking_config = config.get("networking", {})
|
|
||||||
ipv6_config = networking_config.get("ipv6", {"enabled": False})
|
|
||||||
|
|
||||||
output = {"tls": tls_config, "ipv6": ipv6_config}
|
|
||||||
|
|
||||||
print(json.dumps(output))
|
|
||||||
62
docker/main/rootfs/usr/local/nginx/get_nginx_settings.py
Normal file
62
docker/main/rootfs/usr/local/nginx/get_nginx_settings.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
"""Prints the nginx settings as json to stdout."""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from ruamel.yaml import YAML
|
||||||
|
|
||||||
|
sys.path.insert(0, "/opt/frigate")
|
||||||
|
from frigate.util.config import find_config_file
|
||||||
|
|
||||||
|
sys.path.remove("/opt/frigate")
|
||||||
|
|
||||||
|
yaml = YAML()
|
||||||
|
|
||||||
|
config_file = find_config_file()
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(config_file) as f:
|
||||||
|
raw_config = f.read()
|
||||||
|
|
||||||
|
if config_file.endswith((".yaml", ".yml")):
|
||||||
|
config: dict[str, Any] = yaml.load(raw_config)
|
||||||
|
elif config_file.endswith(".json"):
|
||||||
|
config: dict[str, Any] = json.loads(raw_config)
|
||||||
|
except FileNotFoundError:
|
||||||
|
config: dict[str, Any] = {}
|
||||||
|
|
||||||
|
tls_config: dict[str, Any] = config.get("tls", {})
|
||||||
|
tls_config.setdefault("enabled", True)
|
||||||
|
|
||||||
|
networking_config: dict[str, Any] = config.get("networking", {})
|
||||||
|
ipv6_config: dict[str, Any] = networking_config.get("ipv6", {})
|
||||||
|
ipv6_config.setdefault("enabled", False)
|
||||||
|
|
||||||
|
listen_config: dict[str, Any] = networking_config.get("listen", {})
|
||||||
|
listen_config.setdefault("internal", 5000)
|
||||||
|
listen_config.setdefault("external", 8971)
|
||||||
|
|
||||||
|
# handle case where internal port is a string with ip:port
|
||||||
|
internal_port = listen_config["internal"]
|
||||||
|
if type(internal_port) is str:
|
||||||
|
internal_port = int(internal_port.split(":")[-1])
|
||||||
|
listen_config["internal_port"] = internal_port
|
||||||
|
|
||||||
|
# handle case where external port is a string with ip:port
|
||||||
|
external_port = listen_config["external"]
|
||||||
|
if type(external_port) is str:
|
||||||
|
external_port = int(external_port.split(":")[-1])
|
||||||
|
listen_config["external_port"] = external_port
|
||||||
|
|
||||||
|
base_path = os.environ.get("FRIGATE_BASE_PATH", "")
|
||||||
|
|
||||||
|
result: dict[str, Any] = {
|
||||||
|
"tls": tls_config,
|
||||||
|
"ipv6": ipv6_config,
|
||||||
|
"listen": listen_config,
|
||||||
|
"base_path": base_path,
|
||||||
|
}
|
||||||
|
|
||||||
|
print(json.dumps(result))
|
||||||
@ -7,7 +7,7 @@ location ^~ {{ .base_path }}/ {
|
|||||||
# remove base_url from the path before passing upstream
|
# remove base_url from the path before passing upstream
|
||||||
rewrite ^{{ .base_path }}/(.*) /$1 break;
|
rewrite ^{{ .base_path }}/(.*) /$1 break;
|
||||||
|
|
||||||
proxy_pass $scheme://127.0.0.1:8971;
|
proxy_pass $scheme://127.0.0.1:{{ .listen.external_port }};
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection "upgrade";
|
proxy_set_header Connection "upgrade";
|
||||||
|
|||||||
@ -1,15 +1,12 @@
|
|||||||
|
|
||||||
# Internal (IPv4 always; IPv6 optional)
|
# Internal (IPv4 always; IPv6 optional)
|
||||||
listen 5000;
|
listen {{ .listen.internal }};
|
||||||
{{ if .ipv6 }}{{ if .ipv6.enabled }}listen [::]:5000;{{ end }}{{ end }}
|
{{ if .ipv6.enabled }}listen [::]:{{ .listen.internal_port }};{{ end }}
|
||||||
|
|
||||||
|
|
||||||
# intended for external traffic, protected by auth
|
# intended for external traffic, protected by auth
|
||||||
{{ if .tls }}
|
|
||||||
{{ if .tls.enabled }}
|
{{ if .tls.enabled }}
|
||||||
# external HTTPS (IPv4 always; IPv6 optional)
|
# external HTTPS (IPv4 always; IPv6 optional)
|
||||||
listen 8971 ssl;
|
listen {{ .listen.external }} ssl;
|
||||||
{{ if .ipv6 }}{{ if .ipv6.enabled }}listen [::]:8971 ssl;{{ end }}{{ end }}
|
{{ if .ipv6.enabled }}listen [::]:{{ .listen.external_port }} ssl;{{ end }}
|
||||||
|
|
||||||
ssl_certificate /etc/letsencrypt/live/frigate/fullchain.pem;
|
ssl_certificate /etc/letsencrypt/live/frigate/fullchain.pem;
|
||||||
ssl_certificate_key /etc/letsencrypt/live/frigate/privkey.pem;
|
ssl_certificate_key /etc/letsencrypt/live/frigate/privkey.pem;
|
||||||
@ -33,13 +30,7 @@ listen 5000;
|
|||||||
root /etc/letsencrypt/www;
|
root /etc/letsencrypt/www;
|
||||||
}
|
}
|
||||||
{{ else }}
|
{{ else }}
|
||||||
# external HTTP (IPv4 always; IPv6 optional)
|
# (No tls) default to HTTP (IPv4 always; IPv6 optional)
|
||||||
listen 8971;
|
listen {{ .listen.external }};
|
||||||
{{ if .ipv6 }}{{ if .ipv6.enabled }}listen [::]:8971;{{ end }}{{ end }}
|
{{ if .ipv6.enabled }}listen [::]:{{ .listen.external_port }};{{ end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ else }}
|
|
||||||
# (No tls section) default to HTTP (IPv4 always; IPv6 optional)
|
|
||||||
listen 8971;
|
|
||||||
{{ if .ipv6 }}{{ if .ipv6.enabled }}listen [::]:8971;{{ end }}{{ end }}
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
|
|||||||
@ -155,34 +155,33 @@ services:
|
|||||||
|
|
||||||
### Enabling IPv6
|
### Enabling IPv6
|
||||||
|
|
||||||
IPv6 is disabled by default, to enable IPv6 listen.gotmpl needs to be bind mounted with IPv6 enabled. For example:
|
IPv6 is disabled by default, to enable IPv6 modify your Frigate configuration as follows:
|
||||||
|
|
||||||
```
|
```yaml
|
||||||
{{ if not .enabled }}
|
networking:
|
||||||
# intended for external traffic, protected by auth
|
ipv6:
|
||||||
listen 8971;
|
enabled: True
|
||||||
{{ else }}
|
|
||||||
# intended for external traffic, protected by auth
|
|
||||||
listen 8971 ssl;
|
|
||||||
|
|
||||||
# intended for internal traffic, not protected by auth
|
|
||||||
listen 5000;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
becomes
|
### Listen on different ports
|
||||||
|
|
||||||
```
|
You can change the ports Nginx uses for listening using Frigate's configuration file. The internal port (unauthenticated) and external port (authenticated) can be changed independently. You can also specify an IP address using the format `ip:port` if you wish to bind the port to a specific interface. This may be useful for example to prevent exposing the internal port outside the container.
|
||||||
{{ if not .enabled }}
|
|
||||||
# intended for external traffic, protected by auth
|
|
||||||
listen [::]:8971 ipv6only=off;
|
|
||||||
{{ else }}
|
|
||||||
# intended for external traffic, protected by auth
|
|
||||||
listen [::]:8971 ipv6only=off ssl;
|
|
||||||
|
|
||||||
# intended for internal traffic, not protected by auth
|
For example:
|
||||||
listen [::]:5000 ipv6only=off;
|
|
||||||
|
```yaml
|
||||||
|
networking:
|
||||||
|
listen:
|
||||||
|
internal: 127.0.0.1:5000
|
||||||
|
external: 8971
|
||||||
```
|
```
|
||||||
|
|
||||||
|
:::warning
|
||||||
|
|
||||||
|
This setting is for advanced users. For the majority of use cases it's recommended to change the `ports` section of your Docker compose file or use the Docker `run` `--publish` option instead, e.g. `-p 443:8971`. Changing Frigate's ports may break some integrations.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
## Base path
|
## Base path
|
||||||
|
|
||||||
By default, Frigate runs at the root path (`/`). However some setups require to run Frigate under a custom path prefix (e.g. `/frigate`), especially when Frigate is located behind a reverse proxy that requires path-based routing.
|
By default, Frigate runs at the root path (`/`). However some setups require to run Frigate under a custom path prefix (e.g. `/frigate`), especially when Frigate is located behind a reverse proxy that requires path-based routing.
|
||||||
|
|||||||
@ -73,11 +73,19 @@ tls:
|
|||||||
# Optional: Enable TLS for port 8971 (default: shown below)
|
# Optional: Enable TLS for port 8971 (default: shown below)
|
||||||
enabled: True
|
enabled: True
|
||||||
|
|
||||||
# Optional: IPv6 configuration
|
# Optional: Networking configuration
|
||||||
networking:
|
networking:
|
||||||
# Optional: Enable IPv6 on 5000, and 8971 if tls is configured (default: shown below)
|
# Optional: Enable IPv6 on 5000, and 8971 if tls is configured (default: shown below)
|
||||||
ipv6:
|
ipv6:
|
||||||
enabled: False
|
enabled: False
|
||||||
|
# Optional: Override ports Frigate uses for listening (defaults: shown below)
|
||||||
|
# An IP address may also be provided to bind to a specific interface, e.g. ip:port
|
||||||
|
# NOTE: This setting is for advanced users and may break some integrations. The majority
|
||||||
|
# of users should change ports in the docker compose file
|
||||||
|
# or use the docker run `--publish` option to select a different port.
|
||||||
|
listen:
|
||||||
|
internal: 5000
|
||||||
|
external: 8971
|
||||||
|
|
||||||
# Optional: Proxy configuration
|
# Optional: Proxy configuration
|
||||||
proxy:
|
proxy:
|
||||||
|
|||||||
@ -26,7 +26,7 @@ from frigate.api.defs.request.app_body import (
|
|||||||
AppPutRoleBody,
|
AppPutRoleBody,
|
||||||
)
|
)
|
||||||
from frigate.api.defs.tags import Tags
|
from frigate.api.defs.tags import Tags
|
||||||
from frigate.config import AuthConfig, ProxyConfig
|
from frigate.config import AuthConfig, NetworkingConfig, ProxyConfig
|
||||||
from frigate.const import CONFIG_DIR, JWT_SECRET_ENV_VAR, PASSWORD_HASH_ALGORITHM
|
from frigate.const import CONFIG_DIR, JWT_SECRET_ENV_VAR, PASSWORD_HASH_ALGORITHM
|
||||||
from frigate.models import User
|
from frigate.models import User
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ def require_admin_by_default():
|
|||||||
endpoints require admin access unless explicitly overridden with
|
endpoints require admin access unless explicitly overridden with
|
||||||
allow_public(), allow_any_authenticated(), or require_role().
|
allow_public(), allow_any_authenticated(), or require_role().
|
||||||
|
|
||||||
Port 5000 (internal) always has admin role set by the /auth endpoint,
|
Internal port always has admin role set by the /auth endpoint,
|
||||||
so this check passes automatically for internal requests.
|
so this check passes automatically for internal requests.
|
||||||
|
|
||||||
Certain paths are exempted from the global admin check because they must
|
Certain paths are exempted from the global admin check because they must
|
||||||
@ -130,7 +130,7 @@ def require_admin_by_default():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# For all other paths, require admin role
|
# For all other paths, require admin role
|
||||||
# Port 5000 (internal) requests have admin role set automatically
|
# Internal port requests have admin role set automatically
|
||||||
role = request.headers.get("remote-role")
|
role = request.headers.get("remote-role")
|
||||||
if role == "admin":
|
if role == "admin":
|
||||||
return
|
return
|
||||||
@ -148,7 +148,7 @@ def _is_authenticated(request: Request) -> bool:
|
|||||||
Helper to determine if a request is from an authenticated user.
|
Helper to determine if a request is from an authenticated user.
|
||||||
|
|
||||||
Returns True if the request has a valid authenticated user (not anonymous).
|
Returns True if the request has a valid authenticated user (not anonymous).
|
||||||
Port 5000 internal requests are considered anonymous despite having admin role.
|
Internal port requests are considered anonymous despite having admin role.
|
||||||
"""
|
"""
|
||||||
username = request.headers.get("remote-user")
|
username = request.headers.get("remote-user")
|
||||||
return username is not None and username != "anonymous"
|
return username is not None and username != "anonymous"
|
||||||
@ -176,18 +176,18 @@ def allow_any_authenticated():
|
|||||||
Override dependency to allow any authenticated user (bypass admin requirement).
|
Override dependency to allow any authenticated user (bypass admin requirement).
|
||||||
|
|
||||||
Allows:
|
Allows:
|
||||||
- Port 5000 internal requests (have admin role despite anonymous user)
|
- Internal port requests (have admin role despite anonymous user)
|
||||||
- Any authenticated user with a real username (not "anonymous")
|
- Any authenticated user with a real username (not "anonymous")
|
||||||
|
|
||||||
Rejects:
|
Rejects:
|
||||||
- Port 8971 requests with anonymous user (auth disabled, no proxy auth)
|
- External port requests with anonymous user (auth disabled, no proxy auth)
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
@router.get("/authenticated-endpoint", dependencies=[Depends(allow_any_authenticated())])
|
@router.get("/authenticated-endpoint", dependencies=[Depends(allow_any_authenticated())])
|
||||||
"""
|
"""
|
||||||
|
|
||||||
async def auth_checker(request: Request):
|
async def auth_checker(request: Request):
|
||||||
# Port 5000 requests have admin role and should be allowed
|
# Internal port requests have admin role and should be allowed
|
||||||
role = request.headers.get("remote-role")
|
role = request.headers.get("remote-role")
|
||||||
if role == "admin":
|
if role == "admin":
|
||||||
return
|
return
|
||||||
@ -558,12 +558,18 @@ def resolve_role(
|
|||||||
def auth(request: Request):
|
def auth(request: Request):
|
||||||
auth_config: AuthConfig = request.app.frigate_config.auth
|
auth_config: AuthConfig = request.app.frigate_config.auth
|
||||||
proxy_config: ProxyConfig = request.app.frigate_config.proxy
|
proxy_config: ProxyConfig = request.app.frigate_config.proxy
|
||||||
|
networking_config: NetworkingConfig = request.app.frigate_config.networking
|
||||||
|
|
||||||
success_response = Response("", status_code=202)
|
success_response = Response("", status_code=202)
|
||||||
|
|
||||||
|
# handle case where internal port is a string with ip:port
|
||||||
|
internal_port = networking_config.listen.internal
|
||||||
|
if type(internal_port) is str:
|
||||||
|
internal_port = int(internal_port.split(":")[-1])
|
||||||
|
|
||||||
# dont require auth if the request is on the internal port
|
# dont require auth if the request is on the internal port
|
||||||
# this header is set by Frigate's nginx proxy, so it cant be spoofed
|
# this header is set by Frigate's nginx proxy, so it cant be spoofed
|
||||||
if int(request.headers.get("x-server-port", default=0)) == 5000:
|
if int(request.headers.get("x-server-port", default=0)) == internal_port:
|
||||||
success_response.headers["remote-user"] = "anonymous"
|
success_response.headers["remote-user"] = "anonymous"
|
||||||
success_response.headers["remote-role"] = "admin"
|
success_response.headers["remote-role"] = "admin"
|
||||||
return success_response
|
return success_response
|
||||||
|
|||||||
@ -8,6 +8,7 @@ from .config import * # noqa: F403
|
|||||||
from .database import * # noqa: F403
|
from .database import * # noqa: F403
|
||||||
from .logger import * # noqa: F403
|
from .logger import * # noqa: F403
|
||||||
from .mqtt import * # noqa: F403
|
from .mqtt import * # noqa: F403
|
||||||
|
from .network import * # noqa: F403
|
||||||
from .proxy import * # noqa: F403
|
from .proxy import * # noqa: F403
|
||||||
from .telemetry import * # noqa: F403
|
from .telemetry import * # noqa: F403
|
||||||
from .tls import * # noqa: F403
|
from .tls import * # noqa: F403
|
||||||
|
|||||||
@ -1,13 +1,27 @@
|
|||||||
|
from typing import Union
|
||||||
|
|
||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
|
|
||||||
from .base import FrigateBaseModel
|
from .base import FrigateBaseModel
|
||||||
|
|
||||||
__all__ = ["IPv6Config", "NetworkingConfig"]
|
__all__ = ["IPv6Config", "ListenConfig", "NetworkingConfig"]
|
||||||
|
|
||||||
|
|
||||||
class IPv6Config(FrigateBaseModel):
|
class IPv6Config(FrigateBaseModel):
|
||||||
enabled: bool = Field(default=False, title="Enable IPv6 for port 5000 and/or 8971")
|
enabled: bool = Field(default=False, title="Enable IPv6 for port 5000 and/or 8971")
|
||||||
|
|
||||||
|
|
||||||
|
class ListenConfig(FrigateBaseModel):
|
||||||
|
internal: Union[int, str] = Field(
|
||||||
|
default=5000, title="Internal listening port for Frigate"
|
||||||
|
)
|
||||||
|
external: Union[int, str] = Field(
|
||||||
|
default=8971, title="External listening port for Frigate"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class NetworkingConfig(FrigateBaseModel):
|
class NetworkingConfig(FrigateBaseModel):
|
||||||
ipv6: IPv6Config = Field(default_factory=IPv6Config, title="Network configuration")
|
ipv6: IPv6Config = Field(default_factory=IPv6Config, title="IPv6 configuration")
|
||||||
|
listen: ListenConfig = Field(
|
||||||
|
default_factory=ListenConfig, title="Listening ports configuration"
|
||||||
|
)
|
||||||
|
|||||||
@ -14,7 +14,6 @@ RECORD_DIR = f"{BASE_DIR}/recordings"
|
|||||||
TRIGGER_DIR = f"{CLIPS_DIR}/triggers"
|
TRIGGER_DIR = f"{CLIPS_DIR}/triggers"
|
||||||
BIRDSEYE_PIPE = "/tmp/cache/birdseye"
|
BIRDSEYE_PIPE = "/tmp/cache/birdseye"
|
||||||
CACHE_DIR = "/tmp/cache"
|
CACHE_DIR = "/tmp/cache"
|
||||||
FRIGATE_LOCALHOST = "http://127.0.0.1:5000"
|
|
||||||
PLUS_ENV_VAR = "PLUS_API_KEY"
|
PLUS_ENV_VAR = "PLUS_API_KEY"
|
||||||
PLUS_API_HOST = "https://api.frigate.video"
|
PLUS_API_HOST = "https://api.frigate.video"
|
||||||
|
|
||||||
|
|||||||
@ -184,8 +184,13 @@ class RecordingExporter(threading.Thread):
|
|||||||
def get_record_export_command(
|
def get_record_export_command(
|
||||||
self, video_path: str, use_hwaccel: bool = True
|
self, video_path: str, use_hwaccel: bool = True
|
||||||
) -> list[str]:
|
) -> list[str]:
|
||||||
|
# handle case where internal port is a string with ip:port
|
||||||
|
internal_port = self.config.networking.listen.internal
|
||||||
|
if type(internal_port) is str:
|
||||||
|
internal_port = int(internal_port.split(":")[-1])
|
||||||
|
|
||||||
if (self.end_time - self.start_time) <= MAX_PLAYLIST_SECONDS:
|
if (self.end_time - self.start_time) <= MAX_PLAYLIST_SECONDS:
|
||||||
playlist_lines = f"http://127.0.0.1:5000/vod/{self.camera}/start/{self.start_time}/end/{self.end_time}/index.m3u8"
|
playlist_lines = f"http://127.0.0.1:{internal_port}/vod/{self.camera}/start/{self.start_time}/end/{self.end_time}/index.m3u8"
|
||||||
ffmpeg_input = (
|
ffmpeg_input = (
|
||||||
f"-y -protocol_whitelist pipe,file,http,tcp -i {playlist_lines}"
|
f"-y -protocol_whitelist pipe,file,http,tcp -i {playlist_lines}"
|
||||||
)
|
)
|
||||||
@ -217,7 +222,7 @@ class RecordingExporter(threading.Thread):
|
|||||||
for page in range(1, num_pages + 1):
|
for page in range(1, num_pages + 1):
|
||||||
playlist = export_recordings.paginate(page, page_size)
|
playlist = export_recordings.paginate(page, page_size)
|
||||||
playlist_lines.append(
|
playlist_lines.append(
|
||||||
f"file 'http://127.0.0.1:5000/vod/{self.camera}/start/{float(playlist[0].start_time)}/end/{float(playlist[-1].end_time)}/index.m3u8'"
|
f"file 'http://127.0.0.1:{internal_port}/vod/{self.camera}/start/{float(playlist[0].start_time)}/end/{float(playlist[-1].end_time)}/index.m3u8'"
|
||||||
)
|
)
|
||||||
|
|
||||||
ffmpeg_input = "-y -protocol_whitelist pipe,file,http,tcp -f concat -safe 0 -i /dev/stdin"
|
ffmpeg_input = "-y -protocol_whitelist pipe,file,http,tcp -f concat -safe 0 -i /dev/stdin"
|
||||||
|
|||||||
@ -2,12 +2,23 @@
|
|||||||
"label": "Networking configuration",
|
"label": "Networking configuration",
|
||||||
"properties": {
|
"properties": {
|
||||||
"ipv6": {
|
"ipv6": {
|
||||||
"label": "Network configuration",
|
"label": "IPv6 configuration",
|
||||||
"properties": {
|
"properties": {
|
||||||
"enabled": {
|
"enabled": {
|
||||||
"label": "Enable IPv6 for port 5000 and/or 8971"
|
"label": "Enable IPv6 for port 5000 and/or 8971"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"listen": {
|
||||||
|
"label": "Listening ports configuration",
|
||||||
|
"properties": {
|
||||||
|
"internal": {
|
||||||
|
"label": "Internal listening port for Frigate"
|
||||||
|
},
|
||||||
|
"external": {
|
||||||
|
"label": "External listening port for Frigate"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,7 +39,7 @@ export default function ProtectedRoute({
|
|||||||
return <Outlet />;
|
return <Outlet />;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authenticated mode (8971): require login
|
// Authenticated mode (external port): require login
|
||||||
if (!auth.user) {
|
if (!auth.user) {
|
||||||
return (
|
return (
|
||||||
<ActivityIndicator className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" />
|
<ActivityIndicator className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" />
|
||||||
|
|||||||
@ -12,7 +12,7 @@ export function useAllowedCameras() {
|
|||||||
if (
|
if (
|
||||||
auth.user?.role === "viewer" ||
|
auth.user?.role === "viewer" ||
|
||||||
auth.user?.role === "admin" ||
|
auth.user?.role === "admin" ||
|
||||||
!auth.isAuthenticated // anonymous port 5000
|
!auth.isAuthenticated // anonymous internal port
|
||||||
) {
|
) {
|
||||||
// return all cameras
|
// return all cameras
|
||||||
return config?.cameras ? Object.keys(config.cameras) : [];
|
return config?.cameras ? Object.keys(config.cameras) : [];
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user