Skip to content

Versioning and Releases

FreeSDN uses Calendar Versioning (CalVer) in the format YY.MM.PATCH:

ComponentMeaningExample
YYTwo-digit year26 = 2026
MMTwo-digit month (zero-padded)06 = June
PATCHPatch increment within the month, starting at 11, 2, 3

Current release: 26.06.1

Examples of what version numbers communicate:

  • 26.06.1 - first release of June 2026.
  • 26.06.2 - patch release in the same month (bug fix or security patch).
  • 26.07.1 - first release of July 2026.

There is no separate “major” or “minor” bump - the date carries that information. Breaking changes are called out explicitly in the release notes.


FreeSDN targets a monthly release cadence aligned to the CalVer month component. Security patches are released as PATCH increments as soon as they are ready - they do not wait for the monthly cycle.

Dependency update policy:

  • Python and Node packages are not adopted on release day. The 3-day rule applies: new versions are evaluated after they have been on PyPI/npm for at least 72 hours, which catches withdrawn releases and compromised-maintainer incidents.
  • CVE patches override the 3-day rule and are applied as soon as the upstream patch is signed.

Production images are published to the FreeSDN GitHub Container Registry:

ghcr.io/freesdn/freesdn/backend:<version>
ghcr.io/freesdn/freesdn/frontend:<version>

The logdb service is not a pre-built registry image - it is built locally from docker/Dockerfile.logdb (PostgreSQL 18 + TimescaleDB extension) and tagged as freesdn-logdb:local by default. Override the tag with the LOGDB_IMAGE environment variable if you need to pre-build and cache it.

To use the registry images you must first set the image variables in your env file (the compose defaults fall back to locally-built tags). Add these two lines to .env.pro before pulling (substitute the release version):

Terminal window
# In .env.pro - set the registry image tags:
BACKEND_IMAGE=ghcr.io/freesdn/freesdn/backend:26.06.1
EDGE_IMAGE=ghcr.io/freesdn/freesdn/frontend:26.06.1

Then run the standard deploy workflow:

Terminal window
# Pull the images specified above
docker compose --env-file .env.pro pull
# Restart with zero-downtime rolling update (single-host)
docker compose --env-file .env.pro up -d --no-build

Always run migrations after pulling a new release:

Terminal window
docker compose --env-file .env.pro exec api python scripts/migrate.py

Tagged releases are available on the FreeSDN GitHub repository. The public release is a flattened snapshot (no development history):

https://github.com/freesdn/freesdn

The freesdn-agent desktop + headless daemon is distributed separately (MIT-licensed, Python ≥ 3.11, Windows / Linux / macOS):

https://github.com/freesdn/freesdn-agent

Current agent version: v1.0.0 (alpha). The agent uses ECDSA-P256 signed auto-updates (fail-closed - an agent with a bad signature stays on the previous version rather than installing a corrupt update).


The FreeSDN core platform is licensed under the GNU Affero General Public License v3.0 only (AGPL-3.0-only).

Key points of AGPL-3.0:

  • You may use, study, modify, and distribute the software freely.
  • If you run a modified version as a network service (SaaS), you must make the modified source available to users of that service under the same licence.
  • Distribution of binaries requires providing the corresponding source.
  • The licence applies to the entire platform codebase under SPDX-License-Identifier: AGPL-3.0-only.

Full licence text: LICENSE in the repository root, and https://www.gnu.org/licenses/agpl-3.0.html.

The freesdn-agent package is separately licensed under the MIT License. You may embed or redistribute it without the AGPL network-service clause.

Full licence text: LICENSE in the freesdn-agent repository.


  1. Read the release notes for any breaking changes or required migration steps. They are published alongside each tagged release.

  2. Take a database snapshot before upgrading:

    Terminal window
    docker compose --env-file .env.pro exec pg-backup bash -c '
    STAMP=$(date +%Y%m%d_%H%M%S)
    pg_dump -h postgres -U "$PGUSER" -d "${POSTGRES_DB:-freesdn}" \
    | gzip > /backups/preupgrade_$STAMP.sql.gz
    pg_dump -h logdb -U "$LOGDB_USER" -d "$LOGDB_DB" \
    | gzip > /backups/preupgrade_logdb_$STAMP.sql.gz
    '
  3. Pull new images:

    Terminal window
    docker compose --env-file .env.pro pull
  4. Apply migrations (idempotent - safe to run even when already at head):

    Terminal window
    docker compose --env-file .env.pro up -d api
    docker compose --env-file .env.pro exec api python scripts/migrate.py
  5. Start the rest of the stack:

    Terminal window
    docker compose --env-file .env.pro up -d
  6. Verify health:

    Terminal window
    curl -fsS http://localhost:8080/api/v1/health/ready

    Port 8080 is the default Caddy edge port (override via EDGE_HTTP_PORT). In a production stack, the API container port 8000 is not published on the host - only the edge is. To check health from inside the container instead: docker compose --env-file .env.pro exec api python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/api/v1/health/ready', timeout=5); print('ready')"

For full disaster-recovery procedures see docs/DR_PROCEDURE.md in the repository.


The honesty matrix of all 13 adapters (maturity tier, write capability, known limitations) is maintained at docs/SUPPORTED_VENDORS.md in the repository. It is updated with each release. Do not rely on marketing summaries - check that file for your specific vendor before deploying.