Deployment

Deploy Nanosync as a single binary, Docker container, Kubernetes Helm chart, or via Terraform.

Single binary

Nanosync is a single statically-linked binary with no runtime dependencies. State is persisted in an embedded SQLite database.

nanosync start dev --config nanosync.yaml --api-addr :7600 --db-data-dir ./data

Development mode uses embedded SQLite, writes a dev context so CLI commands auto-connect, and colourises logs on TTY. Config is optional.

nanosync start server --config nanosync.yaml --api-addr :7600 --db-data-dir /var/lib/nanosync

Production mode requires a config file and outputs JSON logs by default.

systemd unit file

[Unit]
Description=Nanosync Data Replication
After=network.target

[Service]
Type=simple
User=nanosync
WorkingDirectory=/opt/nanosync
ExecStart=/usr/local/bin/nanosync start server \
  --config /etc/nanosync/nanosync.yaml \
  --db-data-dir /var/lib/nanosync
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
systemctl reload nanosync   # sends SIGHUP — reloads config without restart

Docker

docker run -d \
  --name nanosync \
  -p 7600:7600 \
  -v /etc/nanosync/nanosync.yaml:/etc/nanosync/nanosync.yaml:ro \
  -v /var/lib/nanosync:/var/lib/nanosync \
  -e PG_PASSWORD=secret \
  ghcr.io/nanosyncorg/nanosync:latest \
  start server --config /etc/nanosync/nanosync.yaml --db-data-dir /var/lib/nanosync

Docker Compose

services:
  nanosync:
    image: ghcr.io/nanosyncorg/nanosync:latest
    ports:
      - "7600:7600"
    volumes:
      - ./nanosync.yaml:/etc/nanosync/nanosync.yaml:ro
      - nanosync-data:/var/lib/nanosync
    environment:
      PG_PASSWORD: secret
    command: start server --config /etc/nanosync/nanosync.yaml --db-data-dir /var/lib/nanosync
    depends_on:
      postgres:
        condition: service_healthy

  postgres:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: secret
    command: postgres -c wal_level=logical
    healthcheck:
      test: pg_isready -U postgres
      interval: 5s
      retries: 5

volumes:
  nanosync-data:

Kubernetes (Helm)

helm install nanosync deploy/helm/nanosync/ \
  --namespace nanosync \
  --create-namespace \
  --set image.tag=v0.1.0 \
  --set persistence.enabled=true \
  --set config.existingSecret=nanosync-config

Key Helm values

ValueDefaultDescription
modesinglesingle (one replica) or ha (leader-elected multi-replica)
image.repositoryghcr.io/nanosyncorg/nanosyncContainer image
image.taglatestImage tag
replicaCount1Replicas (clamped to 1 in single mode)
persistence.enabledtrueCreate a PVC for the SQLite state store
persistence.size10GiPVC size
config.existingSecret""Kubernetes Secret name containing nanosync.yaml
ingress.enabledfalseExpose the API via Ingress
serviceMonitor.enabledfalseCreate a Prometheus ServiceMonitor

Config as a Kubernetes Secret

kubectl create secret generic nanosync-config \
  --from-file=nanosync.yaml=./nanosync.yaml \
  --namespace nanosync

Terraform

GCP — Cloud Run

module "nanosync" {
  source  = "./deploy/terraform/gcp/cloud-run"
  project = "my-gcp-project"
  region  = "us-central1"
  image   = "ghcr.io/nanosyncorg/nanosync:v0.1.0"

  config_secret_id = google_secret_manager_secret.nanosync_config.secret_id
}

AWS — ECS Fargate

module "nanosync" {
  source      = "./deploy/terraform/aws/ecs"
  cluster_arn = aws_ecs_cluster.main.arn
  image       = "ghcr.io/nanosyncorg/nanosync:v0.1.0"

  config_secret_arn = aws_secretsmanager_secret.nanosync_config.arn
}

Data directory layout

/var/lib/nanosync/
  nanosync.db        # SQLite: checkpoints, schema history, FSM, run history
  nanosync.db-wal    # SQLite WAL file (normal during operation)
  nanosync.db-shm    # SQLite shared memory file

Upgrading

# Binary
nanosync stop
curl -fsSL https://nanosync.dev/install.sh | sh
nanosync start server --config nanosync.yaml

# Docker
docker pull ghcr.io/nanosyncorg/nanosync:v0.2.0
docker restart nanosync

# Helm
helm upgrade nanosync deploy/helm/nanosync/ --set image.tag=v0.2.0

Schema migrations run automatically on startup.