Nectenda

Self-Hosting Guide

Don't want to self-host? A managed hosted service is coming soon at nectenda.com.

Docker Deployment

Basic Setup

docker run -d \
  --name nectenda \
  -p 1234:1234 \
  -v nectenda-data:/app/data \
  -e JWT_SECRET="$(openssl rand -hex 32)" \
  -e ADMIN_USERNAME="admin" \
  -e ADMIN_PASSWORD="choose-a-strong-password" \
  nectenda/nectenda

Docker Compose

services:
  nectenda:
    image: nectenda/nectenda
    container_name: nectenda
    restart: unless-stopped
    ports:
      - "1234:1234"
    volumes:
      - nectenda-data:/app/data
    environment:
      - JWT_SECRET=your-secret-key-here
      - ADMIN_USERNAME=admin
      - ADMIN_PASSWORD=your-admin-password
      - LOG_LEVEL=info

volumes:
  nectenda-data:

Environment Variables

Variable Required Default Description
JWT_SECRET Yes insecure default Secret for JWT signing. Generate with openssl rand -hex 32. The server warns on startup if not set.
ADMIN_USERNAME No Creates an admin user on first run. Only runs if the user doesn't already exist.
ADMIN_PASSWORD No Password for the auto-created admin user.
PORT No 1234 HTTP/WebSocket listen port.
SQLITE_PATH No /app/data/docs.db Path to the SQLite database file. Must be on the persistent volume.
LOG_LEVEL No info Minimum log level: debug, info, warn, error.

Reverse Proxy

Nectenda uses WebSockets for real-time sync. Your reverse proxy must support WebSocket upgrade.

Nginx

server {
    listen 443 ssl;
    server_name sync.example.com;

    ssl_certificate     /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://127.0.0.1:1234;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 86400;
    }
}

Caddy

sync.example.com {
    reverse_proxy localhost:1234
}

Caddy handles WebSocket upgrade, TLS, and headers automatically.

Plugin Configuration

Once the server is running:

  1. In Obsidian, go to Settings → Nectenda
  2. Set the server URL:
    • Local: ws://localhost:1234
    • With TLS: wss://sync.example.com
  3. Log in with the admin credentials
  4. Generate invite tokens for other users (Admin panel → Generate Invite)

User Management

Backup

The server stores all data in a single SQLite database:

Backup strategy

# Hot backup (SQLite WAL mode is safe for concurrent reads)
docker exec nectenda cp /app/data/docs.db /app/data/docs.db.bak

# Or from the host, copy the volume
docker cp nectenda:/app/data/docs.db ./backup-$(date +%Y%m%d).db

For automated backups, use a cron job or your orchestrator's backup mechanism on the Docker volume.

Restore

docker stop nectenda
docker cp ./backup.db nectenda:/app/data/docs.db
docker start nectenda

Updating

docker pull nectenda/nectenda
docker stop nectenda
docker rm nectenda
# Re-run docker run with the same volume and env vars

Or with Docker Compose:

docker compose pull
docker compose up -d

Data persists across updates via the Docker volume.

Migrating from Hyperfector

The project was renamed from Hyperfector to Nectenda. The Docker volume was renamed with it, from hyperfector-data to nectenda-data. Docker creates the new volume empty, so a server started after the upgrade will not see your existing database until you copy it across:

# Stop the old container first
docker stop hyperfector

# Copy docs.db out of the old volume
docker run --rm -v hyperfector-data:/old -v "$PWD":/backup alpine \
  cp /old/docs.db /backup/docs.db

# Start the new container (creates nectenda-data), then copy the database in
docker compose up -d
docker stop nectenda
docker cp ./docs.db nectenda:/app/data/docs.db
docker start nectenda

Once you have confirmed the new container comes up with your data intact, remove the old volume with docker volume rm hyperfector-data.

The Obsidian plugin id changed too, from hyperfector to nectenda. Each user must delete .obsidian/plugins/hyperfector/ from their vault and install the plugin into .obsidian/plugins/nectenda/. Obsidian keys plugin settings by id, so server URL and login details will need to be entered again.

Security Notes