10 KiB
CLI Client
Sync vaults without Obsidian. Works on servers, automation, backups, headless systems.
Installation
Docker (Recommended)
Pull the latest image:
docker pull ghcr.io/schmelczer/vault-link-cli:latest
npm
Install globally:
npm install -g @schmelczer/local-client-cli
Verify installation:
vaultlink --version
From Source
Build from the repository:
git clone https://github.com/schmelczer/vault-link.git
cd vault-link/frontend/local-client-cli
npm install
npm run build
node dist/cli.js --help
Usage
Basic Usage
vaultlink \
--local-path /path/to/vault \
--remote-uri wss://sync.example.com \
--token your-auth-token \
--vault-name default
Docker Usage
docker run -v /path/to/vault:/vault \
ghcr.io/schmelczer/vault-link-cli:latest \
-l /vault \
-r wss://sync.example.com \
-t your-auth-token \
-v default
Docker Compose
Create docker-compose.yml:
services:
vaultlink-cli:
image: ghcr.io/schmelczer/vault-link-cli:latest
restart: unless-stopped
volumes:
- ./vault:/vault
command:
- "-l"
- "/vault"
- "-r"
- "wss://sync.example.com"
- "-t"
- "your-token"
- "-v"
- "default"
Start the client:
docker compose up -d
Configuration Options
Required Arguments
| Argument | Short | Description | Example |
|---|---|---|---|
--local-path |
-l |
Local directory to sync | /vault |
--remote-uri |
-r |
Server WebSocket URI | wss://sync.example.com |
--token |
-t |
Authentication token | abc123... |
--vault-name |
-v |
Vault name on server | default |
Optional Arguments
| Argument | Default | Description |
|---|---|---|
--sync-concurrency |
1 |
Concurrent file operations |
--max-file-size-mb |
10 |
Max file size in MB |
--ignore-pattern |
- | Glob pattern to ignore (repeatable) |
--websocket-retry-interval-ms |
3500 |
Reconnection interval |
--log-level |
INFO |
Log level: DEBUG, INFO, WARNING, ERROR |
Environment Variables
Alternative to command-line arguments:
export VAULTLINK_LOCAL_PATH="/vault"
export VAULTLINK_REMOTE_URI="wss://sync.example.com"
export VAULTLINK_TOKEN="your-token"
export VAULTLINK_VAULT_NAME="default"
vaultlink
Examples
Basic Sync
Sync a local directory to the server:
vaultlink \
-l ./my-notes \
-r wss://sync.example.com \
-t my-secure-token \
-v personal
With Ignore Patterns
Exclude specific files or directories:
vaultlink \
-l ./vault \
-r wss://sync.example.com \
-t token123 \
-v default \
--ignore-pattern "*.tmp" \
--ignore-pattern ".DS_Store" \
--ignore-pattern "node_modules/**"
Debug Logging
Enable verbose logging:
vaultlink \
-l ./vault \
-r wss://sync.example.com \
-t token123 \
-v default \
--log-level DEBUG
High Concurrency
Faster initial sync:
vaultlink \
-l ./vault \
-r wss://sync.example.com \
-t token123 \
-v default \
--sync-concurrency 5
Large Files
Allow larger file uploads:
vaultlink \
-l ./vault \
-r wss://sync.example.com \
-t token123 \
-v default \
--max-file-size-mb 50
Docker Deployment
Long-Running Sync
Run as a daemon for continuous synchronization:
docker run -d \
--name vaultlink-sync \
--restart unless-stopped \
-v $(pwd)/vault:/vault \
ghcr.io/schmelczer/vault-link-cli:latest \
-l /vault \
-r wss://sync.example.com \
-t your-token \
-v default
Monitor logs:
docker logs -f vaultlink-sync
Health Monitoring
The Docker image includes built-in health checks:
# Check health status
docker ps
# View detailed health info
docker inspect --format='{{json .State.Health}}' vaultlink-sync | jq
Health check verifies:
- Health file exists
- Status updated within last 30 seconds
- WebSocket connection is active
Configure custom health check:
services:
vaultlink-cli:
image: ghcr.io/schmelczer/vault-link-cli:latest
healthcheck:
test: ["CMD", "node", "/app/healthcheck.js"]
interval: 15s
timeout: 5s
retries: 5
start_period: 20s
Read-Only Vault
Mount vault as read-only to prevent local changes:
docker run -d \
-v $(pwd)/vault:/vault:ro \
ghcr.io/schmelczer/vault-link-cli:latest \
-l /vault \
-r wss://sync.example.com \
-t token \
-v default
::: warning
The CLI needs write access to create .vaultlink metadata directory. Mount as read-write or provide a separate writeable directory.
:::
How It Works
Initial Sync
On startup:
- Creates
.vaultlink/directory for metadata - Scans local filesystem
- Uploads all local files to server
- Downloads files from server not present locally
- Resolves conflicts using operational transformation
Real-Time Synchronization
After initial sync:
- Watches filesystem for changes using
fs.watch - Uploads changed files immediately
- Receives real-time updates from server via WebSocket
- Handles bidirectional sync automatically
Graceful Shutdown
On SIGINT (Ctrl+C) or SIGTERM:
- Completes pending uploads
- Closes WebSocket connection cleanly
- Flushes metadata to disk
- Exits gracefully
Use Cases
Automated Backups
Continuously backup vaults to a remote server:
docker run -d \
--name vault-backup \
-v /important/notes:/vault:ro \
ghcr.io/schmelczer/vault-link-cli:latest \
-l /vault -r wss://backup.example.com -t backup-token -v backups
CI/CD Documentation
Sync documentation in automated pipelines:
# In your CI pipeline
docker run \
-v $(pwd)/docs:/vault \
ghcr.io/schmelczer/vault-link-cli:latest \
-l /vault -r wss://docs.example.com -t ci-token -v prod-docs
Multi-Location Sync
Sync between different geographic locations:
# Location A
vaultlink -l /data/vault -r wss://hub.example.com -t token -v shared
# Location B
vaultlink -l /backup/vault -r wss://hub.example.com -t token -v shared
Development Environment
Keep documentation in sync across dev environments:
# In docker-compose.yml for your dev stack
services:
docs-sync:
image: ghcr.io/schmelczer/vault-link-cli:latest
volumes:
- ./docs:/vault
command: ["-l", "/vault", "-r", "wss://docs-server", "-t", "dev-token", "-v", "dev"]
Troubleshooting
Client won't connect
Check server accessibility:
curl https://sync.example.com/vaults/test/ping
Verify WebSocket protocol:
- Use
ws://for HTTP servers - Use
wss://for HTTPS servers
Check authentication:
- Token must match server config
- User must have access to the vault
Permission errors
Docker volume permissions:
# Ensure directory is writable
chmod 755 /path/to/vault
# Check Docker user ID
docker run --rm ghcr.io/schmelczer/vault-link-cli:latest id
SELinux issues:
# Add :z flag to volume mount
docker run -v /path/to/vault:/vault:z ...
Files not syncing
Check ignore patterns:
- View logs to see which files are skipped
- Ensure patterns don't match unintentionally
File size limits:
- Check
--max-file-size-mbsetting - Large files are skipped with a warning
Check metadata:
# View sync metadata
cat /path/to/vault/.vaultlink/metadata.json
High memory usage
Reduce concurrency:
--sync-concurrency 1
Limit file sizes:
--max-file-size-mb 5
Check vault size:
- Very large vaults may need more resources
- Consider splitting into multiple vaults
Connection keeps dropping
Increase retry interval:
--websocket-retry-interval-ms 5000
Check network stability:
# Monitor connection
docker logs -f vaultlink-sync | grep -i websocket
Server timeout settings:
- Verify reverse proxy WebSocket timeout
- Check server
response_timeout_seconds
Advanced Usage
Custom Healthcheck Script
Create your own health monitoring:
#!/bin/bash
HEALTH_FILE="/tmp/vaultlink-health.json"
if [ ! -f "$HEALTH_FILE" ]; then
exit 1
fi
# Check file is recent (within 60 seconds)
if [ $(( $(date +%s) - $(stat -c %Y "$HEALTH_FILE") )) -gt 60 ]; then
exit 1
fi
# Check WebSocket is connected
if ! jq -e '.connected == true' "$HEALTH_FILE" > /dev/null; then
exit 1
fi
exit 0
Automated Recovery
Restart on failure with exponential backoff:
#!/bin/bash
RETRY_DELAY=5
while true; do
vaultlink -l /vault -r wss://server -t token -v default
echo "Client exited, restarting in ${RETRY_DELAY}s..."
sleep $RETRY_DELAY
# Exponential backoff up to 5 minutes
RETRY_DELAY=$((RETRY_DELAY * 2))
if [ $RETRY_DELAY -gt 300 ]; then
RETRY_DELAY=300
fi
done
Integration with systemd
Create /etc/systemd/system/vaultlink-cli.service:
[Unit]
Description=VaultLink CLI Sync
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
Restart=always
RestartSec=10
Environment="VAULTLINK_LOCAL_PATH=/data/vault"
Environment="VAULTLINK_REMOTE_URI=wss://sync.example.com"
Environment="VAULTLINK_TOKEN=your-token"
Environment="VAULTLINK_VAULT_NAME=default"
ExecStart=/usr/local/bin/vaultlink
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable vaultlink-cli
sudo systemctl start vaultlink-cli