HOWTO: Programatically set up SyncThing via the bulit-in CLI command.

Wanted to write some docs for this now that it’s 2025! All of the previous discussion is from several years ago.

This uses syncthing cli which is included in the package, but the concepts should apply to folks looking to integrate into the REST API.


I have two virtual machines, syncOne and syncTwo, and I want to make a shared folder on them. I want to only use the CLI. Maybe these are remote machines, maybe I need to automate this, or maybe I don’t have a web browser handy.

It’s much easier than I expected, but it’s also not clear from the docs. Here’s how to do this.

TL;DR

Install syncthing and run it in the background. Gather each machine’s IDs by running:

syncthing cli show system | jq -r .myID

Syncthing will generate device IDs for you, but it will not generate random folder IDs. Pick a cryptographically secure folder ID by hashing some random bytes:

dd if=/dev/random count=1024 | sha1sum

Then, on each machine, run the same commands to:

  1. introduce this machine to the other:

    syncthing cli config devices add --device-id $OTHER_DEVICE_ID
    
  2. register the folder (syncthing will create it if it does not exist, and will add a .stfolder hidden file if it does exist):

    syncthing cli config folders add --id $FOLDER_ID --path /path/to/folder
    
  3. share the folder to the other device:

    syncthing cli config folders $FOLDER_ID devices add --device-id $OTHER_DEVICE_ID
    

Each of these three steps must be run on both machines.


Here’s a worked example.

Step zero: Setup

First, we install and run syncthing. On both machines, we install syncthing, tmux, and jq:

kimmy@syncOne:~$ sudo apt install -y syncthing tmux jq

Then, pop open a tmux panel and run syncthing in the foreground on both machines.

It looks like this:

2025-01-22 Wed org_20250122_201601_kN19en

I have two terminals open, one connected to each machine. Each terminal is running syncthing in the top and has a shell on the bottom.

Step one: Introduce devices to each other

:point_right: Key idea: Two devices are introduced if they appear in each other’s device list.

There’s no key exchange, you just tell each device the other’s ID. The ID serves as both the username and the password, so keep it secret, keep it safe.

To start, we need to retrieve both device IDs. On syncOne, we have:

kimmy@syncOne:~$ syncthing cli show system | jq -r .myID
DAP76ZM-QQCBKBH-FREZULQ-IVWCASB-EJZOJJS-QE2NRRN-YMN6UAI-UHHHIAV

And on syncTwo, the ID is:

kimmy@syncTwo:~$ syncthing cli show system | jq -r .myID
TLLN7FX-W3IBVGI-GL22U7H-JNP3KOB-4LUSCDV-FZSWFFL-2RDYFFY-IOEXTAE

Now, add syncTwo to syncOne’s device list. On syncOne, run

kimmy@syncOne:~$ syncthing cli config devices add --device-id TLLN7FX-W3IBVGI-GL22U7H-JNP3KOB-4LUSCDV-FZSWFFL-2RDYFFY-IOEXTAE --name syncTwo

Check: After five seconds, syncTwo should show syncOne’s pending invitation:

kimmy@syncTwo:~$ syncthing cli show pending devices
{
  "DAP76ZM-QQCBKBH-FREZULQ-IVWCASB-EJZOJJS-QE2NRRN-YMN6UAI-UHHHIAV": {
    "address": "198.19.249.77:22000",
    "name": "syncOne",
    "time": "2025-01-23T01:24:59Z"
  }
}

Excellent. Accept this invitation by performing the reverse operation on syncTwo (adding syncOne’s ID to syncTwo’s device list):

kimmy@syncTwo:~$ syncthing cli config devices add --device-id DAP76ZM-QQCBKBH-FREZULQ-IVWCASB-EJZOJJS-QE2NRRN-YMN6UAI-UHHHIAV --name syncOne

Step two: Make a folder

Let’s make a pre-existing folder starting on syncOne.

kimmy@syncOne:~$ mkdir mydata
kimmy@syncOne:~$ cd mydata
kimmy@syncOne:~/mydata$ touch hello-world
kimmy@syncOne:~/mydata$ date > foobar
kimmy@syncOne:~/mydata$ ls
foobar  hello-world
kimmy@syncOne:~/mydata$ cat foobar
Wed Jan 22 20:32:06 EST 2025
kimmy@syncOne:~/mydata$ cd
kimmy@syncOne:~$

We first register this folder on syncOne. The two critical parameters are label and path.

kimmy@syncOne:~$ syncthing cli config folders add --label mydata --path ~/mydata
syncthing: error: unexpected HTTP status returned: 400 Bad Request
                  folder has empty ID

Unfortunately, we need to make up a random folder ID. This must not be guessable, so I’ll use the hash of some random bytes as my ID.

kimmy@syncOne:~$ dd if=/dev/urandom count=1024 | sha1sum
...
96feab5b3bd18ed3554abf04b1ce64c5ccee3a96  -

kimmy@syncOne:~$ syncthing cli config folders add --label mydata --path ~/mydata --id 96feab5b3bd18ed3554abf04b1ce64c5ccee3a96

After this, there are two changes on syncOne. First, syncthing created a .stfolder hidden folder inside our folder:

kimmy@syncOne:~$ ls -a mydata/
.  ..  .stfolder  foobar  hello-world

Second, syncOne now lists its own device ID on the folder’s shared device list (in other words, it’s registered to share to itself):

kimmy@syncOne:~$ syncthing cli config folders 96feab5b3bd18ed3554abf04b1ce64c5ccee3a96 dump-json
{
  "id": "96feab5b3bd18ed3554abf04b1ce64c5ccee3a96",
  "label": "mydata",
  "filesystemType": "basic",
  "path": "/home/kimmy/mydata",
  "type": "sendreceive",
  "devices": [
    {
      "deviceID": "DAP76ZM-QQCBKBH-FREZULQ-IVWCASB-EJZOJJS-QE2NRRN-YMN6UAI-UHHHIAV",
      "introducedBy": "",
      "encryptionPassword": ""
    }
  ],
  ... other stuff ...
}

Step three: Share the folder

On syncOne, share the folder to syncTwo:

kimmy@syncOne:~$ syncthing cli config folders 96feab5b3bd18ed3554abf04b1ce64c5ccee3a96 devices add --device-id TLLN7FX-W3IBVGI-GL22U7H-JNP3KOB-4LUSCDV-FZSWFFL-2RDYFFY-IOEXTAE

Check: syncTwo should now show the pending folder invitation.

kimmy@syncTwo:~$ syncthing cli show pending folders
{
  "96feab5b3bd18ed3554abf04b1ce64c5ccee3a96": {
    "offeredBy": {
      "DAP76ZM-QQCBKBH-FREZULQ-IVWCASB-EJZOJJS-QE2NRRN-YMN6UAI-UHHHIAV": {
        "label": "mydata",
        "receiveEncrypted": false,
        "remoteEncrypted": false,
        "time": "2025-01-23T01:41:11Z"
      }
    }
  }
}

Step four: Share the folder back

:point_right: Key idea: Both devices must share the folder to each other.

On syncTwo, we need to add the folder and we also need to share the folder back to syncOne.

kimmy@syncTwo:~$ syncthing cli config folders add --id 96feab5b3bd18ed3554abf04b1ce64c5ccee3a96 --label mydata --path ~/mydata

kimmy@syncTwo:~$ syncthing cli config folders 96feab5b3bd18ed3554abf04b1ce64c5ccee3a96 devices add --device-id DAP76ZM-QQCBKBH-FREZULQ-IVWCASB-EJZOJJS-QE2NRRN-YMN6UAI-UHHHIAV

That’s it! After a short sync period, syncTwo can see the folder and can add to it:

kimmy@syncTwo:~$ ls mydata/
foobar  hello-world
kimmy@syncTwo:~$ echo "Hello from syncTwo" > mydata/syncTwo
kimmy@syncTwo:~$ ls mydata/
foobar  hello-world  syncTwo
kimmy@syncTwo:~$ cat mydata/foobar mydata/syncTwo
Wed Jan 22 20:32:06 EST 2025
Hello from syncTwo

The sync is two-way, so syncOne can also see these changes:

kimmy@syncOne:~$ ls mydata
foobar  hello-world  syncTwo
kimmy@syncOne:~$ cat mydata/foobar mydata/syncTwo
Wed Jan 22 20:32:06 EST 2025
Hello from syncTwo
```2
4 Likes