Hosting

Obsidian on VPS: Self-Hosted Sync Without the Subscription

Want free, private note syncing? Learn how to install and configure a self-hosted Obsidian sync server on a VPS to connect all your devices seamlessly.

is*hosting team 28 Jul 2026 9 min reading
Obsidian on VPS: Self-Hosted Sync Without the Subscription
Table of Contents

Your Obsidian vault lives on your laptop. The moment you open the app on your phone, the notes are days old. Obsidian Sync fixes this, but at $4/month per user on the annual plan, a team of three pays nearly $150/year for a service that moves Markdown files between devices.

This guide covers running your own CouchDB sync backend on an is*hosting VPS, paired with the Self-hosted LiveSync community plugin, so your vault stays current across every device with zero recurring costs beyond the server.

The entire server-side stack, from a blank VPS to a running CouchDB instance behind Nginx, took under four minutes on an is*hosting Start plan.

What You Need Before Setup

Hard requirements:

  • A domain name you control (required for SSL, which is required for iOS and Android)
  • A DNS A record pointing to your VPS IP
  • Obsidian installed on every device you want to sync

CouchDB is light on resources for personal use. The Start plan (2 CPU / 2 GB RAM / 30 GB SSD) handles a personal vault across multiple devices without strain. If your vault is large with many attachments, or you plan to run other services on the same server, the Medium plan’s 40 GB storage and 4 GB RAM provide comfortable headroom. RAM and storage add-ons are available on all plans without reprovisioning.

Load

RAM

CPU

is*hosting plan

Personal vault, 1–5 devices

2 GB

2 CPU

Start ($10.19/mo)

Large vault or multiple users

4 GB

3 CPU

Medium ($21.24/mo)

Every is*hosting plan includes one dedicated IPv4 by default. It’s pre-selected at checkout and already assigned to your server. That public IP is what your domain A record points to. Weekly VPS backups are included on all plans. Docker is not pre-installed; you’ll install it in Step 1.

VPS

A KVM VPS with a dedicated IPv4 and CentOS 9 — enough to run your own CouchDB sync backend, in 40+ locations so you can host close to your devices.

Choose VPS

At provisioning, select CentOS 9 x64 as the operating system.

How to Install the Obsidian Sync Backend on a VPS

How to Install the Obsidian Sync Backend on a VPS

Step 1: Install Docker

Connect over SSH as root. The Docker install script handles everything, including the Compose plugin:

curl -fsSL https://get.docker.com | sh
systemctl enable --now docker

The script adds the Docker CE repo, installs the engine, and enables the service. On a Start plan CentOS 9 x64 VPS, the full install took 90 seconds. The last lines of output confirm success:

INFO: Docker daemon enabled and started
+ sh -c 'docker version'
Client: Docker Engine - Community
 Version:           29.6.0

Verify that both tools are present:

docker --version
docker compose version
Docker version 29.6.0, build fb59821
Docker Compose version v5.2.0

The installer prints a warning about privileged daemon access. This is informational; you can ignore it.

Step 2: Run CouchDB

Create a working directory and set ownership to uid 5984, which is the user CouchDB runs as inside the container:

mkdir -p /opt/couchdb/{data,etc}
chown -R 5984:5984 /opt/couchdb/data /opt/couchdb/etc

Create the Compose file, substituting your own credentials for your_admin_user and your_strong_password:

cat > /opt/couchdb/docker-compose.yml << 'EOF'
services:
  couchdb:
    image: couchdb:latest
    container_name: couchdb-for-ols
    user: 5984:5984
    environment:
      - COUCHDB_USER=your_admin_user
      - COUCHDB_PASSWORD=your_strong_password
    volumes:
      - /opt/couchdb/data:/opt/couchdb/data
      - /opt/couchdb/etc:/opt/couchdb/etc/local.d
    ports:
      - "127.0.0.1:5984:5984"
    restart: unless-stopped
EOF

The 127.0.0.1:5984:5984 binding keeps CouchDB off the public interface. Nginx handles external access.

Start the container:

cd /opt/couchdb
docker compose up -d

Docker pulls the image and starts the container. On the Start plan, this was completed in 10 seconds:

 Network couchdb_default  Creating
 Network couchdb_default  Created
 Container couchdb-for-ols  Creating
 Container couchdb-for-ols  Created
 Container couchdb-for-ols  Starting
 Container couchdb-for-ols  Started

Confirm that CouchDB is responding:

curl -s http://localhost:5984
{"couchdb":"Welcome","version":"3.5.2","git_sha":"5b4d92103","uuid":"2aea31ba5cc04733d9fdbb1c70201f1b","features":["access-ready","partitioned","pluggable-storage-engines","reshard","scheduler"],"vendor":{"name":"The Apache Software Foundation"}}

You’ll notice that docker ps also shows the container has 4369/tcp and 9100/tcp listed. These are internal CouchDB cluster ports. They are not bound to a public interface and do not require firewall rules.

Docker and firewalld: Docker manages its own iptables rules independently of firewalld, so container ports can be reachable from outside even when firewalld is active. CouchDB here is bound only to 127.0.0.1, so it’s not reachable from outside regardless. Still, confirm that firewalld is running and that only the ports Nginx needs are open before the next step:

systemctl enable --now firewalld
firewall-cmd --permanent --add-service=ssh
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload

Verify the active rules:

firewall-cmd --list-all

You should see services: cockpit dhcpd ssh http https (cockpit and dhcpd may vary by image). Port 5984 does not appear here; it remains bound to localhost-only via the Docker port binding.

Step 3: Initialize CouchDB for LiveSync

CouchDB needs cluster and CORS configuration before the plugin can connect. The LiveSync project ships an init script that handles this in a single command:

curl -s -o couchdb-init.sh https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/couchdb/couchdb-init.sh
chmod +x couchdb-init.sh
env hostname=http://localhost:5984 \
    username=your_admin_user \
    password=your_strong_password \
    ./couchdb-init.sh

Successful output (the init script runs 9 API calls; each returns {"ok":true} or ""):

INFO: defaulting to _local
-- Configuring CouchDB by REST APIs... -->
{"ok":true}
""
""
""
""
""
""
""
""
<-- Configuring CouchDB by REST APIs Done!

This took 3 seconds on the Start plan. If you see ERROR: Hostname missing, confirm that the hostname variable includes http:// and port 5984.

Step 4: Set Up Nginx and SSL

Install Nginx and Certbot:

dnf install -y epel-release
dnf install -y nginx certbot python3-certbot-nginx
systemctl enable --now nginx

This installs 31 packages (Nginx, certbot from EPEL, and dependencies) and takes about 7 seconds on the Start plan. One note from the installer output is worth flagging:

Certbot auto renewal timer is not started by default.
Run 'systemctl start certbot-renew.timer' to enable automatic renewals.

Enable it now so your certificate renews automatically:

systemctl enable --now certbot-renew.timer

Create the CouchDB proxy config, replacing your.domain.com with your actual domain:

cat > /etc/nginx/conf.d/couchdb.conf << 'EOF'
server {
    listen 80;
    server_name your.domain.com;
    location / {
        proxy_pass http://localhost:5984;
        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;
    }
}
EOF

Test and reload:

nginx -t
systemctl reload nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Obtain the SSL certificate:

certbot --nginx -d your.domain.com

Certbot prompts for an email address, confirms the Terms of Service, then patches your Nginx config and fetches the certificate. On completion:

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/your.domain.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/your.domain.com/privkey.pem
Deploying certificate to VirtualHost /etc/nginx/conf.d/couchdb.conf
Redirecting all traffic on port 80 to ssl in /etc/nginx/conf.d/couchdb.conf

CORS is configured on the CouchDB side using the init script from Step 3 — there is no need to duplicate the headers in Nginx. Otherwise the browser will receive them twice and reject the preflight request.

Verify the full stack is reachable:

curl -s https://your.domain.com

This should return the same CouchDB welcome JSON from Step 2.

At this point, ss -tlnp on the server shows the final port state:

LISTEN  127.0.0.1:5984   docker-proxy  (CouchDB, localhost only)
LISTEN  0.0.0.0:22       sshd
LISTEN  0.0.0.0:80       nginx         (redirects to 443)
LISTEN  0.0.0.0:443      nginx         (after certbot adds it)

After that, Certbot automatically updates /etc/nginx/conf.d/couchdb.conf: it adds a listen 443 ssl block, the paths to the certificate, and a redirect from port 80 to port 443. Your location block and proxy headers are moved to the port 443 block without any changes. Check the result: nginx -t && cat /etc/nginx/conf.d/couchdb.conf.

Step 5: Connect Obsidian on Your First Device

In Obsidian, go to Settings → Community plugins → Browse, search for Self-hosted LiveSync, install it, and enable it.

Open the plugin settings. The setup wizard launches automatically. Press Start to enter wizard mode. On the Remote Type dropdown, select CouchDB.

Enter your connection details:

  • CouchDB Remote URI: https://your.domain.com
  • Username: your_admin_user
  • Password: your_strong_password
  • Database name: any name you choose (e.g., obsidian-vault)

Click Test on the Test Connection row. If the connection is successful, click Check and Fix database configuration. Fix buttons appear for any items that need attention; press each one. When all Fix buttons are replaced by checkmarks, proceed.

On the Confidentiality configuration screen, enable End-to-End encryption and set a passphrase. The plugin docs describe this as strongly recommended; it encrypts notes before they leave the device. Enable Path Obfuscation as well to encrypt filenames.

On the Sync Settings screen, select LiveSync for real-time sync (changes propagate within seconds) or Periodic for lower bandwidth usage. Press Apply. When All done! appears, the setup is complete. The plugin immediately offers to copy a Setup URI. Save it, as you will need it for every additional device.

Step 6: Connect Additional Devices

On any subsequent device, install the Self-hosted LiveSync plugin, then click Use in the wizard (or Use the copied setup URI from the command palette). Paste the URI and enter the passphrase. At the How would you like to set it up? prompt, select Set it up as secondary or subsequent device. Initialization runs automatically. When the sync indicators in the status bar clear, run Reload app without saving. The vault syncs down.

How to Use Self-hosted LiveSync: Status, Conflicts, and Attachments

How to Use Self-hosted LiveSync: Status, Conflicts, and Attachments

Reading Sync Status

The plugin shows its state in the Obsidian status bar:

  • 💤 means LiveSync is enabled and waiting for changes
  • ⚡️ means synchronization is in progress
  • ⚠ means an error has occurred; check plugin settings

Do not close Obsidian while ⚡️ is showing, especially after renaming or deleting files. The plugin will attempt to resume if interrupted, but letting it finish cleanly avoids edge-case conflicts.

Resolving Conflicts

If you edit the same note on two devices while offline and both come back online, CouchDB retains both versions. LiveSync surfaces this as a conflict indicator on the note. Open it, and the plugin shows both versions side by side with options to keep one or merge them manually. Simple conflicts (for example, appended text with no overlap) are merged automatically.

Excluding Large Attachments

If your vault contains large PDFs or media files that you don’t need on every device, go to LiveSync settings → Sync and configure excluded folders or toggle the file type filters. This keeps the CouchDB database from growing with files that don’t need to travel over the network.

How to Update

Updating CouchDB

Back up the data directory first:

tar -czf /root/couchdb-backup-$(date +%Y%m%d).tar.gz /opt/couchdb/data

Then update:

cd /opt/couchdb
docker compose pull
docker compose up -d --force-recreate

Docker pulls the latest CouchDB image, replaces the container, and re-mounts the same data volume. Your vault data, credentials, and configuration survive the update.

is*hosting includes free weekly VPS-level backups on all plans, but a targeted CouchDB archive takes two seconds and restores with one command. That’s faster than restoring a full server snapshot when an update goes sideways.

Compacting the Database Periodically

CouchDB accumulates revision history over time. Compact every few months to reclaim disk space:

curl -X POST http://your_admin_user:your_strong_password@localhost:5984/obsidian-vault/_compact \
  -H "Content-Type: application/json"

Response on success: {"ok":true}

Updating the LiveSync Plugin

In Obsidian, go to Settings → Community plugins. When an update is available, an Update button appears next to Self-hosted LiveSync. Before updating on any device, confirm the status bar shows 💤 and that no sync is in progress.

Backup Storage

Free weekly VPS backups on every plan — so a CouchDB update gone wrong never costs you your synced vault.

Explore

What You’ve Got Running

From a blank CentOS 9 x64 VPS to a running CouchDB instance with Nginx installed: under 4 minutes. The server-side stack uses about 900 MB of disk (Docker engine, CouchDB image, Nginx, and dependencies) on top of the base OS, leaving 26 GB free on the Start plan’s 30 GB SSD. CouchDB at idle draws around 50–80 MB of RAM on a quiet vault; the full stack including OS overhead sits comfortably under 500 MB, well within the Start plan’s 2 GB.

What you have: real-time Obsidian vault sync across Windows, macOS, Linux, iOS, and Android, end-to-end encrypted at rest in CouchDB, served over HTTPS from a server you control, at the cost of an is*hosting Start plan at $10.19/month on the annual plan ($11.99 month-to-month).

Obsidian Sync at the same scale for a solo user is $48/year; for two users it is $96/year. The VPS covers itself in the first month if you would otherwise run two Sync subscriptions.

For the initial server baseline before running these steps, the Linux VPS setup guide covers SSH hardening and system configuration. If you want monitoring on the CouchDB endpoint so you know immediately if sync goes down, Uptime Kuma on a VPS runs on the same server without conflict.

FAQ

What is Self-hosted LiveSync and how does it work?

Self-hosted LiveSync is a community plugin (11,000+ GitHub stars) that enables cross-device replication for Obsidian notes. It uses CouchDB — a document database with conflict-aware replication built into its protocol — as a backend. The plugin translates vault changes into CouchDB documents and propagates them to all connected devices within seconds.

What actually runs on the VPS?

Only two components run on the server:

  • CouchDB: A single Docker container (couchdb:latest) listening on 127.0.0.1:5984.
  • Nginx: A reverse proxy that terminates SSL and forwards HTTPS traffic to CouchDB on localhost.

On your devices, nothing extra runs beyond the Obsidian app itself with the plugin installed.

What are the key compatibility rules and requirements before starting?

  • You cannot run Self-hosted LiveSync alongside official Obsidian Sync, iCloud, or other filesystem sync solutions on the same vault (doing so will cause conflicts).
  • End-to-end encryption is supported and strongly recommended. Without a passphrase set, your notes land in CouchDB as plaintext.
  • iOS requires a valid SSL certificate to reach CouchDB — mobile sync will not work over plain HTTP.

Why choose Self-hosted LiveSync over official Obsidian Sync?

  • Cost savings for multiple users. Obsidian Sync costs $4/month ($48/year) per user. For 2–3 users ($96–$144/year), running a CouchDB container on a small VPS is significantly cheaper.
  • Complete data control. Notes never leave servers you control, which is essential for researchers, lawyers, and engineers under NDA obligations.
  • Jurisdiction and latency. Hosting on a provider like is*hosting (with 40+ data center locations across Europe, Asia, and North America) allows you to place the sync backend in a specific compliance jurisdiction or closer to your devices for lower latency.
Dedicated Server

For when VPS isn’t enough.

From $66.67/mo