Installation
An Edge Site runs the edge controller, a service that catalogs recordings in local storage, reports them to Foxglove, and uploads them to your Primary Site when you import them.
If your Edge Site runs edge-site Helm chart 0.0.32 or earlier, read Upgrade from chart 0.0.x before you install chart 0.1.0 or later. The catalog location changes between these Helm chart versions, so the new controller must be configured to open the existing catalog.
System requirements
The edge controller runs on Linux on AMD64 or ARM64 processors. The host needs:
- HTTPS access to
api.foxglove.dev(port 443)- IP addresses:
104.18.20.210and104.18.21.210, which can change without notice - Used for: control plane communication, health reporting, and recording metadata
- IP addresses:
- Network access to your Primary Site's storage, for uploads:
- Foxglove-hosted:
storage.googleapis.com - Self-hosted or bring your own storage (BYOS): your upload bucket's endpoint
- Foxglove-hosted:
- A system certificate authority (CA) bundle to verify HTTPS connections, such as the
ca-certificatespackage on Debian-based distributions - A directory containing your recordings, called the storage directory
- A writable directory for the edge controller's catalog, on local disk rather than network storage
Minimal and container base images often don't include a CA bundle. Kubernetes installs also need a Kubernetes cluster, kubectl, and Helm.
If configuring firewall rules, allowlist both IP addresses for api.foxglove.dev. The service uses DNS round-robin, so the edge controller may connect to either IP.
Create a site and site token
You must be an organization admin to complete these steps.
- On the Sites settings page, click "Add Edge Site".
- Enter a name and create the site. You can configure retention later.
- Open the site's details and click "Create new token". Copy the site token.
Admins can also create site tokens with the API. Generate an API key with the siteTokens.create capability from the API key settings page, and use it to create site tokens.
Each site needs its own site token. Run one edge controller per site.
Install the edge controller
The edge controller is available for AMD64 and ARM64 in these forms:
- A
.debpackage, for Debian-based Linux distributions with systemd - A statically linked Linux executable
- A Docker image
- The
edge-siteHelm chart, for Kubernetes
- Debian package
- Statically linked Linux executable
- Docker image
- Kubernetes
Download the latest foxglove-edge-controller package for your architecture from the Edge Site releases page, saving it as /tmp/foxglove-edge-controller.deb. Saving to /tmp rather than your home directory means apt won't print a harmless Download is performed unsandboxed notice during installation. Install with apt, which also installs the package's dependencies:
sudo apt update
sudo apt install /tmp/foxglove-edge-controller.deb
The package installs:
- The
foxglove-edge-controllerexecutable in/usr/bin - A
foxglove-edge-controllersystemd service, enabled at boot, that runs as thefoxglovesystem user - The configuration file
/etc/foxglove/edge-controller/envfile - The storage directory
/srv/foxglove/edge-controller/storageand the catalog directory/var/lib/foxglove/edge-controller
The package starts the service right away. It fails until you configure it, and systemd stops retrying after a few failures. This is expected.
Download the latest foxglove-edge-controller binary for your architecture from the Edge Site releases page, saving it as foxglove-edge-controller. Make the file executable, and check its version:
chmod +x foxglove-edge-controller
./foxglove-edge-controller --version
The executable has no library dependencies, but it reads the system CA certificate bundle. If the host has no bundle, set SSL_CERT_FILE to the path of a CA bundle file.
Move the executable to an appropriate location for your system.
A multi-platform image is available at us-central1-docker.pkg.dev/foxglove-images/images/edge-controller. Mount your recordings at /storage and a persistent catalog volume at /index. For example, create a named volume for the catalog:
docker volume create foxglove-edge-controller-index
The run command mounts both directories. Pull the latest version from the Edge Site releases page, using its version number as the tag rather than latest:
docker pull us-central1-docker.pkg.dev/foxglove-images/images/edge-controller:<version>
Add the Foxglove Helm repository:
helm repo add foxglove https://helm-charts.foxglove.dev
helm repo update
Create a foxglove namespace in your cluster:
kubectl create namespace foxglove
The chart needs two Persistent Volume Claims in the foxglove namespace. Create them before you install the chart; until they're bound, the edge controller pod stays Pending.
The recording storage claim holds your recordings and is mounted at /data/storage. The default claim name is edge-controller-storage-claim; override it with the edgeController.storageClaim value. For example:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: edge-controller-storage-claim
spec:
accessModes:
- ReadWriteOnce
storageClassName: "..."
resources:
requests:
storage: ...
The chart runs a single edge controller pod, so ReadWriteOnce is enough. Use ReadWriteMany only if pods on other nodes also mount the volume, for example to write recordings, and your storage provisioner supports it.
The catalog claim holds the edge controller's catalog and is mounted at /data/index. Back it with block storage rather than network storage. The default claim name is edge-controller-index-claim; override it with the edgeController.indexClaim value. For example:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: edge-controller-index-claim
spec:
accessModes:
- ReadWriteOnce
storageClassName: "..."
resources:
requests:
storage: ...
These examples use dynamic provisioning. To bind a PersistentVolume you've already created, add its name as volumeName.
The edge controller reads recordings only from the recording storage claim. Leave the recordingStorage values at their defaults. Storing recordings in S3-compatible object storage isn't supported: if recordingStorage.provider isn't local, the chart doesn't mount the recording storage claim, and the edge controller exits at startup.
Configure the edge controller
Set the site token you created, storage paths, and recording discovery mode. The examples below select watch mode for the Debian package, executable, and Docker image, and the recordings API for Kubernetes. To change the mode, or to set filters and automatic import, see Manage data.
Choose your upload settings before starting the controller. All examples explicitly select Foxglove-hosted uploads; change them if you use a self-hosted or BYOS Primary Site.
For logging and metrics options, see Logging and Monitoring.
- Debian package
- Statically linked Linux executable
- Docker image
- Kubernetes
Edit /etc/foxglove/edge-controller/envfile. The package keeps your changes when you upgrade. Use this reference configuration, setting FOXGLOVE_SITE_TOKEN to your site token:
# FOXGLOVE_SITE_TOKEN authenticates the edge controller to the API and should
# be obtained from the Foxglove Sites settings page. A particular Foxglove site
# should have at most a single associated edge controller.
FOXGLOVE_SITE_TOKEN=
# STORAGE_ROOT is the path from which the edge controller will read your
# recordings. Recording paths will appear in Foxglove relative to this path.
# The directory must exist before startup.
STORAGE_ROOT=/srv/foxglove/edge-controller/storage
# VARDIR must be a read-writable path where the edge controller can store
# internal state.
VARDIR=/var/lib/foxglove/edge-controller
# WATCH_MODE enables discovery of completed MCAP files under STORAGE_ROOT and
# its subdirectories.
WATCH_MODE=true
# WATCH_INCLUDE_SUFFIXES is a comma-delimited list of file suffixes that should
# be treated as recordings. More granular filtering can be accomplished using
# regexes and exclusions.
WATCH_INCLUDE_SUFFIXES=.mcap
#WATCH_INCLUDE_REGEX=
#WATCH_EXCLUDE_SUFFIXES=
#WATCH_EXCLUDE_REGEX=
# WATCH_AUTO_IMPORT_PATTERN is a glob pattern matched against each recording's
# path relative to STORAGE_ROOT. Matching recordings are uploaded to Foxglove
# automatically. * matches across directory separators, so *.mcap also matches
# recordings in nested subdirectories. Leave commented out to import recordings
# manually.
#WATCH_AUTO_IMPORT_PATTERN=**/*.mcap
# ENABLE_SERVER turns on the recordings API, which listens on SERVER_ADDRESS
# (default 127.0.0.1) and PORT (default 9099). To submit recordings through
# the API instead of watch mode, set WATCH_MODE=false and ENABLE_SERVER=true.
# Clients on other hosts or containers also need SERVER_ADDRESS=0.0.0.0.
#ENABLE_SERVER=true
#SERVER_ADDRESS=0.0.0.0
# FOXGLOVE_LOG_OUTPUT controls how logs are routed. When running the edge
# controller under systemd, this should typically be "journald". Other options
# are "json" or "text" to output JSON or human-readable logs to stderr.
FOXGLOVE_LOG_OUTPUT=journald
# PRIMARY_SITE_MODE should be set to self-managed or hosted according to the
# deployment mode of the primary site to which the edge controller reports.
# See Upload settings for self-hosted/BYOS.
PRIMARY_SITE_MODE=hosted
#INBOX_STORAGE_PROVIDER=
#INBOX_BUCKET_NAME=
The file is readable only by root and the foxglove user because it holds your site token.
Manage the process environment directly, or create edge-controller.env using this reference configuration. The executable also loads a .env file from its working directory.
# FOXGLOVE_SITE_TOKEN authenticates the edge controller to the API and should
# be obtained from the Foxglove Sites settings page. A particular Foxglove site
# should have at most a single associated edge controller.
FOXGLOVE_SITE_TOKEN=
# STORAGE_ROOT is the path from which the edge controller will read your
# recordings. Recording paths will appear in Foxglove relative to this path.
# The directory must exist before startup.
STORAGE_ROOT=/path/to/recordings
# VARDIR must be a read-writable path where the edge controller can store
# internal state.
VARDIR=/path/to/catalog
# WATCH_MODE enables discovery of completed MCAP files under STORAGE_ROOT and
# its subdirectories.
WATCH_MODE=true
# WATCH_INCLUDE_SUFFIXES is a comma-delimited list of file suffixes that should
# be treated as recordings. More granular filtering can be accomplished using
# regexes and exclusions.
WATCH_INCLUDE_SUFFIXES=.mcap
#WATCH_INCLUDE_REGEX=
#WATCH_EXCLUDE_SUFFIXES=
#WATCH_EXCLUDE_REGEX=
# WATCH_AUTO_IMPORT_PATTERN is a glob pattern matched against each recording's
# path relative to STORAGE_ROOT. Matching recordings are uploaded to Foxglove
# automatically. * matches across directory separators, so *.mcap also matches
# recordings in nested subdirectories. Leave commented out to import recordings
# manually.
#WATCH_AUTO_IMPORT_PATTERN=**/*.mcap
# ENABLE_SERVER turns on the recordings API, which listens on SERVER_ADDRESS
# (default 127.0.0.1) and PORT (default 9099). To submit recordings through
# the API instead of watch mode, set WATCH_MODE=false and ENABLE_SERVER=true.
# Clients on other hosts or containers also need SERVER_ADDRESS=0.0.0.0.
#ENABLE_SERVER=true
#SERVER_ADDRESS=0.0.0.0
# FOXGLOVE_LOG_OUTPUT controls how logs are routed. When running the edge
# controller under systemd, this should typically be "journald". Other options
# are "json" or "text" to output JSON or human-readable logs to stderr.
FOXGLOVE_LOG_OUTPUT=text
# PRIMARY_SITE_MODE should be set to self-managed or hosted according to the
# deployment mode of the primary site to which the edge controller reports.
# See Upload settings for self-hosted/BYOS.
PRIMARY_SITE_MODE=hosted
#INBOX_STORAGE_PROVIDER=
#INBOX_BUCKET_NAME=
Set both paths: without explicit settings, STORAGE_ROOT and VARDIR use the working directory.
Create edge-controller.env using this reference configuration, then pass it to the container with --env-file:
# FOXGLOVE_SITE_TOKEN authenticates the edge controller to the API and should
# be obtained from the Foxglove Sites settings page. A particular Foxglove site
# should have at most a single associated edge controller.
FOXGLOVE_SITE_TOKEN=
# VARDIR must be a read-writable path where the edge controller can store
# internal state. The edge controller Docker image uses the /index directory by
# default. It is not typically necessary to override this configuration.
#VARDIR=/index
# WATCH_MODE enables discovery of completed MCAP files under STORAGE_ROOT and
# its subdirectories.
WATCH_MODE=true
# WATCH_INCLUDE_SUFFIXES is a comma-delimited list of file suffixes that should
# be treated as recordings. More granular filtering can be accomplished using
# regexes and exclusions.
WATCH_INCLUDE_SUFFIXES=.mcap
#WATCH_INCLUDE_REGEX=
#WATCH_EXCLUDE_SUFFIXES=
#WATCH_EXCLUDE_REGEX=
# WATCH_AUTO_IMPORT_PATTERN is a glob pattern matched against each recording's
# path relative to STORAGE_ROOT. Matching recordings are uploaded to Foxglove
# automatically. * matches across directory separators, so *.mcap also matches
# recordings in nested subdirectories. Leave commented out to import recordings
# manually.
#WATCH_AUTO_IMPORT_PATTERN=**/*.mcap
# ENABLE_SERVER turns on the recordings API, which listens on SERVER_ADDRESS
# (default 127.0.0.1) and PORT (default 9099). To submit recordings through
# the API instead of watch mode, set WATCH_MODE=false and ENABLE_SERVER=true.
# Docker port publishing requires SERVER_ADDRESS=0.0.0.0.
#ENABLE_SERVER=true
#SERVER_ADDRESS=0.0.0.0
# FOXGLOVE_LOG_OUTPUT controls how logs are routed. Options are "json" for
# JSON-structured output (useful for log aggregators) or "text" for
# human-readable logs to stderr.
FOXGLOVE_LOG_OUTPUT=text
# PRIMARY_SITE_MODE should be set to self-managed or hosted according to the
# deployment mode of the primary site to which the edge controller reports.
# See Upload settings for self-hosted/BYOS.
PRIMARY_SITE_MODE=hosted
#INBOX_STORAGE_PROVIDER=
#INBOX_BUCKET_NAME=
The Helm chart reads your site token from a Secret named foxglove-site-token. Create it in the foxglove namespace before installing the chart:
kubectl create secret generic foxglove-site-token \
--from-literal=FOXGLOVE_SITE_TOKEN='fox_st_...' --namespace foxglove
For other ways to create a Secret, see Create a Secret. After changing the Secret, restart the pod so it reads the new token:
kubectl delete pod site-controller-0 -n foxglove
Configure the chart with a values.yaml file. The chart sets the storage and catalog paths and enables the recordings API. This example turns watch mode off, so your recording process submits files through the API:
# The chart loads FOXGLOVE_SITE_TOKEN from the foxglove-site-token Secret.
globals:
upload:
# Use hosted for Foxglove-hosted storage. See Upload settings for self-hosted/BYOS.
primarySiteMode: hosted
edgeController:
env:
# Set true to discover MCAP files instead of submitting them through the API.
- name: WATCH_MODE
value: '"false"'
# Write structured logs to stderr for kubectl logs or a log collector.
- name: FOXGLOVE_LOG_OUTPUT
value: json
The chart writes edgeController.env values without quotes. Wrap values that YAML would read as booleans or numbers in a second pair of quotes, as shown for WATCH_MODE.
See Upload settings for the provider-specific values and Secrets. Other chart settings are listed in values.yaml.
Configure storage
In watch mode, the edge controller monitors the storage directory recursively — recordings in nested subdirectories are detected too. See Watch mode for details. The storage directory must exist when the edge controller starts.
The edge controller keeps its catalog, a SQLite database named controller.db, in VARDIR. Keep the catalog for the life of the site. Starting with a new catalog for an existing site creates a new site epoch. Foxglove then treats recordings reported from the earlier catalog as removed from the Edge Site, and a controller still using the earlier catalog stops.
- Debian package
- Statically linked Linux executable
- Docker image
- Kubernetes
Configure the STORAGE_ROOT environment variable with the directory that holds your recordings. This will serve as the edge controller's data directory.
Configure the VARDIR environment variable with the directory you want to store the internal state of the edge controller.
The edge controller runs as the foxglove user and group under systemd. The foxglove user must have read and write access to the STORAGE_ROOT and VARDIR directories and their contents. The package creates /srv/foxglove/edge-controller/storage writable by all users, and /var/lib/foxglove/edge-controller owned by foxglove.
Depending on your system configuration, you may need to adjust directory ownership or group permissions to allow the foxglove user to access files created by other users (for example, your recording process). Common approaches include:
- Adding the
foxgloveuser to a shared group that has access to the storage directorysudo usermod -a -G $GROUP foxglove - Adjusting directory ownership and permissions (for example, using
chownandchmod)
If you make permission changes after starting the edge controller service, restart the service for the permission changes to take effect.
sudo systemctl restart foxglove-edge-controller
Configure the STORAGE_ROOT environment variable with the directory that holds your recordings. This will serve as the edge controller's data directory. Set STORAGE_ROOT and VARDIR to absolute paths.
The user running the edge controller executable must have read and write access to the STORAGE_ROOT and VARDIR directories and their contents.
Depending on your system configuration, you may need to adjust directory ownership or group permissions to allow the edge controller process to access files created by other users (for example, your recording process). Common approaches include:
- Running the edge controller as a user that already has access to the storage directory
- Adding the edge controller's user to a shared group that has access to the storage directory
- Adjusting directory ownership and permissions (for example, using
chownandchmod)
After making permission changes, restart the edge controller process for them to take effect.
When using the edge controller Docker image, bind-mount your data directory to /storage inside the container. You do not need to configure STORAGE_ROOT.
No additional permission setup is required. Docker handles filesystem access through the bind-mount.
Mount the same named Docker volume at /index whenever you replace the container, so it continues using the site's catalog.
The chart mounts the recording storage claim at /data/storage and the catalog claim at /data/index. Keep the catalog claim (edgeController.indexClaim) when you reinstall or upgrade the release.
Run the edge controller
- Debian package
- Statically linked Linux executable
- Docker image
- Kubernetes
After editing the envfile, restart the service and check its status:
sudo systemctl restart foxglove-edge-controller
systemctl status foxglove-edge-controller
View the logs with journalctl:
journalctl -u foxglove-edge-controller
Load your environment file and start the executable:
(set -a; . ./edge-controller.env; set +a; ./foxglove-edge-controller)
To keep the edge controller running, start it with your system's process manager, and restart it when it exits with an error.
Start the container, with the version you pulled:
docker run --detach \
--name foxglove-edge-controller \
--restart unless-stopped \
--mount type=volume,src=foxglove-edge-controller-index,dst=/index \
--mount type=bind,src=/path/to/recording/storage,dst=/storage \
--publish 9099:9099 \
--publish 6001:6001 \
--env-file edge-controller.env \
us-central1-docker.pkg.dev/foxglove-images/images/edge-controller:<version>
Port 9099 serves the recordings API, if enabled, and port 6001 serves Prometheus metrics. Omit the --publish options you don't need.
View the logs:
docker logs foxglove-edge-controller
Install the latest chart:
helm install foxglove-edge-site foxglove/edge-site \
--values ./values.yaml \
--namespace foxglove
View info about the deployment, and the edge controller's logs:
helm list -n foxglove
kubectl logs -n foxglove statefulset/site-controller
Verify the installation
Check the edge controller's logs for a site initialized line with the site's ID, name, and epoch. The edge controller logs this line when it has connected to Foxglove. For errors that stop the edge controller, see FAQ.
On the Sites settings page, the site shows as "Online". The site's details show the edge controller version under "Site Version".
If the recordings API is on, check it with the liveness endpoint, which returns {"status":"ok"}:
curl http://localhost:9099/v1/liveness
On Kubernetes, forward the service port to your machine, then request the endpoint:
kubectl port-forward -n foxglove service/edge-controller 8888:8888
curl http://localhost:8888/v1/liveness
Create an Ingress
On Kubernetes, the chart exposes the recordings API through the edge-controller service on port 8888. To submit recordings from outside your cluster, create an Ingress. For example, save this as edge-controller-ingress.yaml, replacing the ingress class and host with your cluster's values:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: edge-controller
namespace: foxglove
spec:
ingressClassName: your-ingress-class
rules:
- host: edge-site.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: edge-controller
port:
number: 8888
Apply the configuration, then check the liveness endpoint through the Ingress:
kubectl apply -f edge-controller-ingress.yaml
curl http://edge-site.example.com/v1/liveness
Uninstall
Uninstalling the edge controller leaves your recordings and its catalog in place. If you install it again for the same site, use the same catalog; see Configure storage.
Next steps
To add recordings to your site, see Manage data.
Support
For additional support, email support@foxglove.dev.