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.
Install syncthing and run it in the background. Gather each machine's IDs by running:
syncthing cli show system | jq -r .myIDSyncthing will generate device IDs, 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 | sha1sumThen, on each machine, run:
# Introduce this device to the other device
syncthing cli config devices add --device-id $OTHER_DEVICE_ID
# Register the folder (syncthing will create
# it if it does not exist. If it does exist,
# syncthing will add a `.stfolder`
# hidden file to it.)
syncthing cli config folders add --id $FOLDER_ID --path /path/to/folder
# Share the folder to the other device
syncthing cli config folders $FOLDER_ID devices add --device-id $OTHER_DEVICE_IDEach of these three steps must be run on both machines.
Here's a worked example:
First, we install and run syncthing. On both machines, we install syncthing, tmux, and jq:
kimmy@syncOne:~$ sudo apt install -y syncthing tmux jqThen, pop open a tmux panel and run syncthing in the foreground on both machines.
It looks like this:
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.
๐ 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-UHHHIAVAnd on syncTwo, the ID is:
kimmy@syncTwo:~$ syncthing cli show system | jq -r .myID
TLLN7FX-W3IBVGI-GL22U7H-JNP3KOB-4LUSCDV-FZSWFFL-2RDYFFY-IOEXTAENow, 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 syncTwoCheck: 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 syncOneLet'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 IDUnfortunately, 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 96feab5b3bd18ed3554abf04b1ce64c5ccee3a96After 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-worldSecond, 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 ...
}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-IOEXTAECheck: 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"
}
}
}
}๐ 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-UHHHIAVThat'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 syncTwoThe 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