syncthing-rest-api

title: syncthing-rest-api(7)

summary: REST API

text:
# syncthing-rest-api(7)

## NAME
syncthing-rest-api - REST API

Syncthing exposes a REST interface over HTTP on the GUI port. This is used by the GUI (from Javascript) and can be used by other processes wishing to control Syncthing. In most cases both the input and output data is in JSON format. The interface is subject to change.

## API KEY
To use the REST API an API key must be set and used. The API key can be generated in the GUI, or set in the configuration/gui/apikey element in the configuration file. To use an API key, set the request header X-API-Key to the API key value, or set it as a Bearer token in the Authorization header. For example, curl -X POST -H "X-API-Key: abc123" http://localhost:8384/rest/... or curl -X POST -H "Authorization: Bearer abc123" http://localhost:8384/rest/... can be used to invoke with curl (add -k flag when using HTTPS with a Syncthing generated or self signed certificate).

One exception to this requirement is /rest/noauth, you do not need an API key to use those endpoints. This way third-party devices and services can do simple calls that don’t expose sensitive information without having to expose your API key.

## RESULT PAGINATION
Some GET endpoints take optional page and perpage arguments for pagination. No more than perpage (defaults to 65536 if not given) result entries are returned in an array. To access further entries, passing the page parameter will advance in the results by that many pages. The actually used parameters are always returned as attributes in the response object.

## SYSTEM ENDPOINTS

### GET /rest/system/browse
Returns a list of directories matching the path given by the optional parameter current. The path can use patterns as described in Go’s filepath package <https://pkg.go.dev/path/filepath#Match>. A ‘*’ will always be appended to the given path (e.g. /tmp/ matches all its subdirectories). If the option current is not given, filesystem root paths are returned.

```
$ curl -H "X-API-Key: yourkey" localhost:8384/rest/system/browse | json_pp
[

    "/"
]
$ curl -H "X-API-Key: yourkey" localhost:8384/rest/system/browse?current=/var/ | json_pp
[

    "/var/backups/",

    "/var/cache/",

    "/var/lib/",

    "/var/local/",

    "/var/lock/",

    "/var/log/",

    "/var/mail/",

    "/var/opt/",

    "/var/run/",

    "/var/spool/",

    "/var/tmp/"
]
$ curl -H "X-API-Key: yourkey" localhost:8384/rest/system/browse?current=/var/*o | json_pp
[

    "/var/local/",

    "/var/lock/",

    "/var/log/",

    "/var/opt/",

    "/var/spool/"
]
```

### GET /rest/system/config (DEPRECATED)
Deprecated since version v1.12.0: This endpoint still works as before but is deprecated. Use /rest/config instead.

Returns the current configuration.

```
{

  "version": 35,

  "folders": [

    {

      "id": "default",

      "label": "Default Folder",

      "filesystemType": "basic",

      "path": "...",

      "type": "sendreceive",

      "devices": [

        {

          "deviceID": "...",

          "introducedBy": "",

          "encryptionPassword": ""

        }

      ],

      "rescanIntervalS": 3600,

      "fsWatcherEnabled": true,

      "fsWatcherDelayS": 10,

      "ignorePerms": false,

      "autoNormalize": true,

      "minDiskFree": {

        "value": 1,

        "unit": "%"

      },

      "versioning": {

        "type": "",

        "params": {},

        "cleanupIntervalS": 3600,

        "fsPath": "",

        "fsType": "basic"

      },

      "copiers": 0,

      "pullerMaxPendingKiB": 0,

      "hashers": 0,

      "order": "random",

      "ignoreDelete": false,

      "scanProgressIntervalS": 0,

      "pullerPauseS": 0,

      "maxConflicts": -1,

      "disableSparseFiles": false,

      "paused": false,

      "markerName": ".stfolder",

      "copyOwnershipFromParent": false,

      "modTimeWindowS": 0,

      "maxConcurrentWrites": 16,

      "disableFsync": false,

      "blockPullOrder": "standard",

      "copyRangeMethod": "standard",

      "caseSensitiveFS": false,

      "junctionsAsDirs": true

    }

  ],

  "devices": [

    {

      "deviceID": "...",

      "name": "Laptop",

      "addresses": [

        "dynamic",

        "tcp://192.168.1.2:22000"

      ],

      "compression": "metadata",

      "certName": "",

      "introducer": false,

      "skipIntroductionRemovals": false,

      "introducedBy": "",

      "paused": false,

      "allowedNetworks": [],

      "autoAcceptFolders": false,

      "maxSendKbps": 0,

      "maxRecvKbps": 0,

      "ignoredFolders": [

        {

          "time": "2022-01-09T19:09:52Z",

          "id": "br63e-wyhb7",

          "label": "Foo"

        }

      ],

      "maxRequestKiB": 0,

      "untrusted": false,

      "remoteGUIPort": 0

    }

  ],

  "gui": {

    "enabled": true,

    "address": "127.0.0.1:8384",

    "unixSocketPermissions": "",

    "user": "Username",

    "password": "$2a$10$ZFws69T4FlvWwsqeIwL.TOo5zOYqsa/.TxlUnsGYS.j3JvjFTmxo6",

    "authMode": "static",

    "useTLS": false,

    "apiKey": "k1dnz1Dd0rzTBjjFFh7CXPnrF12C49B1",

    "insecureAdminAccess": false,

    "theme": "default",

    "insecureSkipHostcheck": false,

    "insecureAllowFrameLoading": false

  },

  "ldap": {

    "address": "",

    "bindDN": "",

    "transport": "plain",

    "insecureSkipVerify": false,

    "searchBaseDN": "",

    "searchFilter": ""

  },

  "options": {

    "listenAddresses": [

      "default"

    ],

    "globalAnnounceServers": [

      "default"

    ],

    "globalAnnounceEnabled": true,

    "localAnnounceEnabled": true,

    "localAnnouncePort": 21027,

    "localAnnounceMCAddr": "[ff12::8384]:21027",

    "maxSendKbps": 0,

    "maxRecvKbps": 0,

    "reconnectionIntervalS": 60,

    "relaysEnabled": true,

    "relayReconnectIntervalM": 10,

    "startBrowser": true,

    "natEnabled": true,

    "natLeaseMinutes": 60,

    "natRenewalMinutes": 30,

    "natTimeoutSeconds": 10,

    "urAccepted": 0,

    "urSeen": 0,

    "urUniqueId": "...",

    "urURL": "https://data.syncthing.net/newdata",

    "urPostInsecurely": false,

    "urInitialDelayS": 1800,

    "autoUpgradeIntervalH": 12,

    "upgradeToPreReleases": false,

    "keepTemporariesH": 24,

    "cacheIgnoredFiles": false,

    "progressUpdateIntervalS": 5,

    "limitBandwidthInLan": false,

    "minHomeDiskFree": {

      "value": 1,

      "unit": "%"

    },

    "releasesURL": "https://upgrades.syncthing.net/meta.json",

    "alwaysLocalNets": [],

    "overwriteRemoteDeviceNamesOnConnect": false,

    "tempIndexMinBlocks": 10,

    "unackedNotificationIDs": [

      "authenticationUserAndPassword"

    ],

    "trafficClass": 0,

    "setLowPriority": true,

    "maxFolderConcurrency": 0,

    "crURL": "https://crash.syncthing.net/newcrash",

    "crashReportingEnabled": true,

    "stunKeepaliveStartS": 180,

    "stunKeepaliveMinS": 20,

    "stunServers": [

      "default"

    ],

    "maxConcurrentIncomingRequestKiB": 0,

    "announceLANAddresses": true,

    "sendFullIndexOnUpgrade": false,

    "featureFlags": [],

    "connectionLimitEnough": 0,

    "connectionLimitMax": 0

  },

  "remoteIgnoredDevices": [

    {

      "time": "2022-01-09T20:02:01Z",

      "deviceID": "...",

      "name": "...",

      "address": "192.168.0.20:22000"

    }

  ],

  "defaults": {

    "folder": {

      "id": "",

      "label": "",

      "filesystemType": "basic",

      "path": "~",

      "type": "sendreceive",

      "devices": [

        {

          "deviceID": "...",

          "introducedBy": "",

          "encryptionPassword": ""

        }

      ],

      "rescanIntervalS": 3600,

      "fsWatcherEnabled": true,

      "fsWatcherDelayS": 10,

      "ignorePerms": false,

      "autoNormalize": true,

      "minDiskFree": {

        "value": 1,

        "unit": "%"

      },

      "versioning": {

        "type": "",

        "params": {},

        "cleanupIntervalS": 3600,

        "fsPath": "",

        "fsType": "basic"

      },

      "copiers": 0,

      "pullerMaxPendingKiB": 0,

      "hashers": 0,

      "order": "random",

      "ignoreDelete": false,

      "scanProgressIntervalS": 0,

      "pullerPauseS": 0,

      "maxConflicts": 10,

      "disableSparseFiles": false,

      "paused": false,

      "markerName": ".stfolder",

      "copyOwnershipFromParent": false,

      "modTimeWindowS": 0,

      "maxConcurrentWrites": 16,

      "disableFsync": false,

      "blockPullOrder": "standard",

      "copyRangeMethod": "standard",

      "caseSensitiveFS": false,

      "junctionsAsDirs": false

    },

    "device": {

      "deviceID": "",

      "name": "",

      "addresses": [

        "dynamic"

      ],

      "compression": "metadata",

      "certName": "",

      "introducer": false,

      "skipIntroductionRemovals": false,

      "introducedBy": "",

      "paused": false,

      "allowedNetworks": [],

      "autoAcceptFolders": false,

      "maxSendKbps": 0,

      "maxRecvKbps": 0,

      "ignoredFolders": [],

      "maxRequestKiB": 0,

      "untrusted": false,

      "remoteGUIPort": 0

    }

  }
}
```

### GET /rest/system/config/insync (DEPRECATED)
Deprecated since version v1.12.0: This endpoint still works as before but is deprecated. Use /rest/config/restart-required instead.

Returns whether the config is in sync, i.e. whether the running configuration is the same as that on disk.

```
{

  "configInSync": true
}
```

### POST /rest/system/config (DEPRECATED)
Deprecated since version v1.12.0: This endpoint still works as before but is deprecated. Use Config Endpoints instead.

Post the full contents of the configuration, in the same format as returned by the corresponding GET request. When posting the configuration succeeds, the posted configuration is immediately applied, except for changes that require a restart. Query /rest/config/restart-required to check if a restart is required.

This endpoint is the main point to control Syncthing, even if the change only concerns a very small part of the config: The usual workflow is to get the config, modify the needed parts and post it again.

### GET /rest/system/connections
NOTE:

Return format changed in versions 0.13.0, 0.14.14, 1.2.0, 1.19.0, 1.23.0 and 1.25.0.

Returns the list of configured devices and some metadata associated with them.

The connection types are tcp-client, tcp-server, relay-client, relay-server, quic-client and quic-server.

```
{

  "connections": {

    "DOVII4U-SQEEESM-VZ2CVTC-CJM4YN5-QNV7DCU-5U3ASRL-YVFG6TH-W5DV5AA": {

      "address": "",

      "at": "0001-01-01T00:00:00Z",

      "clientVersion": "",

      "connected": false,

      "inBytesTotal": 0,

      "isLocal": false,

      "outBytesTotal": 0,

      "paused": false,

      "startedAt": "0001-01-01T00:00:00Z",

      "type": ""

    },

    "UYGDMA4-TPHOFO5-2VQYDCC-7CWX7XW-INZINQT-LE4B42N-4JUZTSM-IWCSXA4": {

      "address": "",

      "at": "0001-01-01T00:00:00Z",

      "clientVersion": "",

      "connected": false,

      "inBytesTotal": 0,

      "isLocal": false,

      "outBytesTotal": 0,

      "paused": false,

      "startedAt": "0001-01-01T00:00:00Z",

      "type": ""

    },

    "YZJBJFX-RDBL7WY-6ZGKJ2D-4MJB4E7-ZATSDUY-LD6Y3L3-MLFUYWE-AEMXJAC": {

      "address": "127.0.0.1:22002",

      "at": "2015-11-07T17:29:47.691548971+01:00",

      "clientVersion": "v0.12.1",

      "connected": true,

      "inBytesTotal": 556,

      "isLocal": true,

      "outBytesTotal": 550,

      "paused": false,

      "startedAt": "2015-11-07T00:09:47Z",

      "type": "tcp-client"

    }

  },

  "total": {

    "at": "2015-11-07T17:29:47.691637262+01:00",

    "inBytesTotal": 1479,

    "outBytesTotal": 1318

  }
}
```

### GET /rest/system/discovery
Returns the contents of the local discovery cache.

```
{

  "LGFPDIT7SKNNJVJZA4FC7QNCRKCE753K72BW5QD2FOZ7FRFEP57Q": [

    "192.162.129.11:22000"

  ]
}
```

### POST /rest/system/discovery
NOTE:

Removed in v0.12.0.

Post with the query parameters device and addr to add entries to the discovery cache.

```
curl -X POST http://127.0.0.1:8384/rest/system/discovery?device=LGFPDIT7SKNNJVJZA4FC7QNCRKCE753K72BW5QD2FOZ7FRFEP57Q\&addr=192.162.129.11:22000
# Or with the X-API-Key header:
curl -X POST --header "X-API-Key: TcE28kVPdtJ8COws1JdM0b2nodj77WeQ" http://127.0.0.1:8384/rest/system/discovery?device=LGFPDIT7SKNNJVJZA4FC7QNCRKCE753K72BW5QD2FOZ7FRFEP57Q\&addr=192.162.129.11:22000
```

### POST /rest/system/error/clear
Post with empty to body to remove all recent errors.

### GET /rest/system/error
NOTE:

Return format changed in 0.12.0.

Returns the list of recent errors.

```
{

  "errors": [

    {

      "when": "2014-09-18T12:59:26.549953186+02:00",

      "message": "This is an error string"

    }

  ]
}
```

### POST /rest/system/error
Post with an error message in the body (plain text) to register a new error. The new error will be displayed on any active GUI clients.

### GET /rest/system/log
Added in version 0.12.0.

Returns the list of recent log entries. The optional since parameter limits the results to message newer than the given timestamp in RFC 3339 <https://datatracker.ietf.org/doc/html/rfc3339.html> format.

```
{

  "messages": [

    {

      "when": "2014-09-18T12:59:26.549953186+02:00",

      "message": "This is a log entry"

    }

  ]
}
```

### GET /rest/system/log.txt
Returns the same information, formatted as a text log instead of a JSON object.

### GET /rest/system/loglevels
Added in version 2.0.0.

Returns the set of log facilities and their current log level.

```
{

  "levels": {

    "api": "INFO",

    "beacon": "INFO",

    ...

    "versioner": "INFO",

    "watchaggregator": "INFO"

  },

  "packages": {

    "api": "REST API",

    "beacon": "Multicast and broadcast discovery",

    ...

    "versioner": "File versioning",

    "watchaggregator": "Filesystem event watcher"

  }
}
```

### POST /rest/system/loglevels
Added in version 2.0.0.

Changes the log level for specified facilities. Post an object with the log facilites as keys and desired log level (DEBUG, INFO, WARN, or ERROR) as the values.

```
$ curl -H X-API-Key:abc123 -d '{"beacon":"DEBUG","discovery":"WARN"}' 'http://localhost:8384/rest/system/loglevels'
```

### GET /rest/system/paths
Added in version 1.21.0.

Returns the path locations used internally for storing configuration, database, and others.

```
{

  "auditLog": "/home/user/.local/share/syncthing/audit-${timestamp}.log",

  "baseDir-config": "/home/user/.config/syncthing",

  "baseDir-data": "/home/user/.local/share/syncthing",

  "baseDir-userHome": "/home/user",

  "certFile": "/home/user/.config/syncthing/cert.pem",

  "config": "/home/user/.config/syncthing/config.xml",

  "csrfTokens": "/home/user/.config/syncthing/csrftokens.txt",

  "database": "/home/user/.local/share/syncthing/index-v2",

  "defFolder": "/home/user/Sync",

  "guiAssets": "/home/user/src/syncthing/gui",

  "httpsCertFile": "/home/user/.config/syncthing/https-cert.pem",

  "httpsKeyFile": "/home/user/.config/syncthing/https-key.pem",

  "keyFile": "/home/user/.config/syncthing/key.pem",

  "logFile": "-",

  "panicLog": "/home/user/.local/share/syncthing/panic-${timestamp}.log"
}
```

### POST /rest/system/pause
Pause the given device or all devices.

Takes the optional parameter device (device ID). When omitted, pauses all devices. Returns status 200 and no content upon success, or status 500 and a plain text error on failure.

### GET /rest/system/ping
Returns a {"ping": "pong"} object.

```
{

  "ping": "pong"
}
```

### POST /rest/system/ping
Returns a {"ping": "pong"} object.

### POST /rest/system/reset
Post with empty body to erase the current index database and restart Syncthing. With no query parameters, the entire database is erased from disk. By specifying the folder parameter with a valid folder ID, only information for that folder will be erased:

```
curl -X POST -H "X-API-Key: abc123" http://localhost:8384/rest/system/reset?folder=ab1c2-def3g
```

Caution: See --reset-database for .stfolder creation side-effect and caution regarding mountpoints.

### POST /rest/system/restart
Post with empty body to immediately restart Syncthing.

### POST /rest/system/resume
Resume the given device or all devices.

Takes the optional parameter device (device ID). When omitted, resumes all devices. Returns status 200 and no content upon success, or status 500 and a plain text error on failure.

### POST /rest/system/shutdown
Post with empty body to cause Syncthing to exit and not restart.

### GET /rest/system/status
Returns information about current system status and resource usage. The CPU percent value has been deprecated from the API and will always report 0.

```
{

  "alloc": 30618136,

  "connectionServiceStatus": {

    "dynamic+https://relays.syncthing.net/endpoint": {

      "error": null,

      "lanAddresses": [

        "relay://23.92.71.120:443/?id=53STGR7-YBM6FCX-PAZ2RHM-YPY6OEJ-WYHVZO7-PCKQRCK-PZLTP7T-434XCAD&pingInterval=1m0s&networkTimeout=2m0s&sessionLimitBps=0&globalLimitBps=0&statusAddr=:22070&providedBy=canton7"

      ],

      "wanAddresses": [

        "relay://23.92.71.120:443/?id=53STGR7-YBM6FCX-PAZ2RHM-YPY6OEJ-WYHVZO7-PCKQRCK-PZLTP7T-434XCAD&pingInterval=1m0s&networkTimeout=2m0s&sessionLimitBps=0&globalLimitBps=0&statusAddr=:22070&providedBy=canton7"

      ]

    },

    "tcp://0.0.0.0:22000": {

      "error": null,

      "lanAddresses": [

        "tcp://0.0.0.0:22000"

      ],

      "wanAddresses": [

        "tcp://0.0.0.0:22000"

      ]

    }

  },

  "cpuPercent": 0,

  "discoveryEnabled": true,

  "discoveryErrors": {

    "global@https://discovery-v4-1.syncthing.net/v2/": "500 Internal Server Error",

    "global@https://discovery-v4-2.syncthing.net/v2/": "Post https://discovery-v4-2.syncthing.net/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)",

    "global@https://discovery-v4-3.syncthing.net/v2/": "Post https://discovery-v4-3.syncthing.net/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)",

    "global@https://discovery-v6-1.syncthing.net/v2/": "Post https://discovery-v6-1.syncthing.net/v2/: dial tcp [2001:470:28:4d6::5]:443: connect: no route to host",

    "global@https://discovery-v6-2.syncthing.net/v2/": "Post https://discovery-v6-2.syncthing.net/v2/: dial tcp [2604:a880:800:10::182:a001]:443: connect: no route to host",

    "global@https://discovery-v6-3.syncthing.net/v2/": "Post https://discovery-v6-3.syncthing.net/v2/: dial tcp [2400:6180:0:d0::d9:d001]:443: connect: no route to host"

  },

  "discoveryStatus": {

    "IPv4 local": {

      "error": null

    },

    "IPv6 local": {

      "error": null

    },

    "global@https://discovery-v4-1.syncthing.net/v2/": {

      "error": "500 Internal Server Error"

    },

    "global@https://discovery-v4-2.syncthing.net/v2/": {

      "error": "Post https://discovery-v4-2.syncthing.net/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)"

    },

    "global@https://discovery-v4-3.syncthing.net/v2/": {

      "error": "Post https://discovery-v4-3.syncthing.net/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)"

    },

    "global@https://discovery-v6-1.syncthing.net/v2/": {

      "error": "Post https://discovery-v6-1.syncthing.net/v2/: dial tcp [2001:470:28:4d6::5]:443: connect: no route to host"

    },

    "global@https://discovery-v6-2.syncthing.net/v2/": {

      "error": "Post https://discovery-v6-2.syncthing.net/v2/: dial tcp [2604:a880:800:10::182:a001]:443: connect: no route to host"

    },

    "global@https://discovery-v6-3.syncthing.net/v2/": {

      "error": "Post https://discovery-v6-3.syncthing.net/v2/: dial tcp [2400:6180:0:d0::d9:d001]:443: connect: no route to host"

    }

  },

  "discoveryMethods": 8,

  "goroutines": 49,

  "lastDialStatus": {

      "tcp://10.20.30.40": {

        "when": "2019-05-16T07:41:23Z",

        "error": "dial tcp 10.20.30.40:22000: i/o timeout"

      },

      "tcp://172.16.33.3:22000": {

        "when": "2019-05-16T07:40:43Z",

        "ok": true

      },

      "tcp://83.233.120.221:22000": {

        "when": "2019-05-16T07:41:13Z",

        "error": "dial tcp 83.233.120.221:22000: connect: connection refused"

      }

  },

  "myID": "P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2",

  "pathSeparator": "/",

  "startTime": "2016-06-06T19:41:43.039284753+02:00",

  "sys": 42092792,

  "themes": [

    "default",

    "dark"

  ],

  "tilde": "/Users/jb",

  "uptime": 2635
}
```

Added in version 1.2.0: The lastDialStatus dictionary contains the last error (or null for success) for each peer address that Syncthing has attempted to contact. The connectionServiceStatus entries gained "error": null attributes where previously there would be no error attribute at all in the success case.

Added in version 1.18.0: The discoveryStatus dictionary lists all configured discovery methods, not only failed ones like the now deprecated discoveryErrors. Each entry is an object itself (for consistency with other fields), where a null value for the error attribute means the method is running successfully. This effectively deprecates the discoveryMethods attribute as well, which now always matches the number of entries in discoveryStatus.

### GET /rest/system/upgrade
Checks for a possible upgrade and returns an object describing the newest version and upgrade possibility.

```
{

  "latest": "v0.14.47",

  "majorNewer": false,

  "newer": true,

  "running": "v0.14.46"
}
```

### POST /rest/system/upgrade
Perform an upgrade to the newest released version and restart. Does nothing if there is no newer version than currently running.

### GET /rest/system/version
Returns the current Syncthing version information.

```
{

  "arch": "amd64",

  "longVersion": "syncthing v0.10.27+3-gea8c3de (go1.4 darwin-amd64 default) jb@syno 2015-03-16 11:01:29 UTC",

  "os": "darwin",

  "version": "v0.10.27+3-gea8c3de"
}
```

## CONFIG ENDPOINTS

### Config Endpoints
Added in version 1.12.0.

These endpoints facilitate access and modification of the configuration in a granular way. Config sent to the endpoints must be in the same format as returned by the corresponding GET request. When posting the configuration succeeds, the posted configuration is immediately applied, except for changes that require a restart. Query /rest/config/restart-required to check if a restart is required.

For all endpoints supporting PATCH, it takes the existing config and unmarshals the given JSON object on top of it. This means all child objects will replace the existing objects, not extend them. For example for RawListenAddresses in options, which is an array of strings, sending {RawListenAddresses: ["tcp://10.0.0.2"]} will replace all existing listen addresses.

### /rest/config
GET returns the entire config and PUT replaces it.

### /rest/config/restart-required
GET returns whether a restart of Syncthing is required for the current config to take effect.

### /rest/config/folders, /rest/config/devices
GET returns all folders respectively devices as an array. PUT takes an array and POST a single object. In both cases if a given folder/device already exists, it’s replaced, otherwise a new one is added.

### /rest/config/folders/*id*, /rest/config/devices/*id*
Put the desired folder- respectively device-ID in place of *id*. GET returns the folder/device for the given ID, PUT replaces the entire config, PATCH replaces only the given child objects and DELETE removes the folder/device.

### /rest/config/defaults/folder, /rest/config/defaults/device
GET returns a template folder / device configuration object with all default values, which only needs a unique ID to be applied. PUT replaces the default config (omitted values are reset to the hard-coded defaults), PATCH replaces only the given child objects.

### /rest/config/defaults/ignores
Added in version 1.19.0.

GET returns an object with a single lines attribute listing ignore patterns to be used by default on folders, as an array of single-line strings. PUT replaces the default ignore patterns from an object of the same format.

### /rest/config/options, /rest/config/ldap, /rest/config/gui
GET returns the respective object, PUT replaces the entire object and PATCH replaces only the given child objects.

NOTE:

The gui.password configuration option has special handling to accept already hashed passwords. Any valid bcrypt hash is stored verbatim, while a plaintext password is first hashed.

## CLUSTER ENDPOINTS
Concerns the mesh network structure.

### DELETE /rest/cluster/pending/devices
Added in version 1.18.0.

Remove records about a pending remote device which tried to connect. Valid values for the device parameter are those from the corresponding GET /rest/cluster/pending/devices endpoint.

```
$ curl -X DELETE -H "X-API-Key: abc123" http://localhost:8384/rest/cluster/pending/devices?device=P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2
```

Returns status 200 and no content upon success, or status 500 and a plain text error on failure. A PendingDevicesChanged event will be generated in response.

For a more permanent effect, also for future connections from the same device ID, the device should be ignored in the configuration instead.

### GET /rest/cluster/pending/devices
Added in version 1.13.0.

Lists remote devices which have tried to connect, but are not yet configured in our instance.

```
{

  "P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2": {

    "time": "2020-03-18T11:43:07Z",

    "name": "Friend Joe",

    "address": "192.168.1.2:22000"

  }
}
```

### DELETE /rest/cluster/pending/folders
Added in version 1.18.0.

Remove records about a pending folder announced from a remote device. Valid values for the folder and device parameters are those from the corresponding GET /rest/cluster/pending/folders endpoint. The device parameter is optional and affects announcements of this folder from the given device, or from any device if omitted.

```
$ curl -X DELETE -H "X-API-Key: abc123" http://localhost:8384/rest/cluster/pending/folders?folder=cpkn4-57ysy&device=P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2
```

Returns status 200 and no content upon success, or status 500 and a plain text error on failure. A PendingFoldersChanged event will be generated in response.

For a more permanent effect, also for future announcements of the same folder ID, the folder should be ignored in the configuration instead.

### GET /rest/cluster/pending/folders
Added in version 1.13.0.

Lists folders which remote devices have offered to us, but are not yet shared from our instance to them. Takes the optional device parameter to only return folders offered by a specific remote device. Other offering devices are also omitted from the result.

```
{

  "cpkn4-57ysy": {

    "offeredBy": {

      "P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2": {

        "time": "2020-03-18T11:43:07Z",

        "label": "Joe's folder",

        "receiveEncrypted": true,

        "remoteEncrypted": false

      },

      "DOVII4U-SQEEESM-VZ2CVTC-CJM4YN5-QNV7DCU-5U3ASRL-YVFG6TH-W5DV5AA": {

        "time": "2020-03-01T10:12:13Z",

        "label": "Jane's and Joe's folder",

        "receiveEncrypted": false,

        "remoteEncrypted": false

      }

    }

  },

  "abcde-fghij": {

    "offeredBy": {

      "P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2": {

        "time": "2020-03-18T11:43:07Z",

        "label": "MyPics",

        "receiveEncrypted": false,

        "remoteEncrypted": false

      }

    }

  }
}
```

## FOLDER ENDPOINTS
Runtime state of the individual shared folders.

### GET /rest/folder/errors
Added in version 0.14.53.

Takes one mandatory parameter, folder, and returns the list of errors encountered during scanning or pulling.

The results can be paginated using the common pagination parameters.

```
{

  "folder": "nnhic-sxuae",

  "errors": [

    {

      "path": "noperm.txt",

      "error": "hashing: open /path/to/folder/noperm.txt: permission denied"

    }

  ],

  "page": 1,

  "perpage": 100
}
```

### GET /rest/folder/pullerrors (DEPRECATED)
Deprecated since version v0.14.53: This endpoint still works as before but is deprecated. Use GET /rest/folder/errors instead, which returns the same information.

See https://github.com/syncthing/syncthing/commit/d510e3cca3d5caae42121fa206b3decc981ae59e

### GET /rest/folder/versions
Added in version 0.14.44.

Takes one mandatory parameter, folder, and returns the list of archived files that could be recovered. How many versions are available depends on the File Versioning configuration. Each entry specifies when the file version was archived as the versionTime, the modTime when it was last modified before being archived, and the size in bytes.

```
{

  "dir1/dir2/bar": [

    {

      "versionTime": "2022-02-06T20:44:12+01:00",

      "modTime": "2021-01-14T13:21:22+01:00",

      "size": 4

    }

  ],

  "baz": [

    {

      "versionTime": "2022-02-06T20:44:20+01:00",

      "modTime": "2021-01-14T13:23:49+01:00",

      "size": 4

    }

  ],

  "foo": [

    {

      "versionTime": "2022-02-06T20:55:31+01:00",

      "modTime": "2022-02-06T20:44:13+01:00",

      "size": 4

    },

    {

      "versionTime": "2022-02-06T20:44:20+01:00",

      "modTime": "2021-01-14T13:21:16+01:00",

      "size": 4

    }

  ]
}
```

### POST /rest/folder/versions
Restore archived versions of a given set of files. Expects an object with attributes named after the relative file paths, with timestamps as values matching valid versionTime entries in the corresponding GET /rest/folder/versions response object.

Takes the mandatory parameter folder (folder ID). Returns an object containing any error messages that occurred during restoration of the file, with the file path as attribute name.

```
curl -X POST -H X-API-key:... http://127.0.0.1:8384/rest/folder/versions?folder=default -d '{

  "dir1/dir2/bar": "2022-02-06T20:44:12+01:00",

  "baz": "2022-02-06T20:44:20+01:00"
}'
```

## DATABASE ENDPOINTS

### GET /rest/db/browse
Returns the directory tree of the global model. Directories are always JSON objects (map/dictionary), and files are always arrays of modification time and size. The first integer is the files modification time, and the second integer is the file size.

The call takes one mandatory folder parameter and two optional parameters. Optional parameter levels defines how deep within the tree we want to dwell down (0 based, defaults to unlimited depth) Optional parameter prefix defines a prefix within the tree where to start building the structure.

```
$ curl -s http://localhost:8384/rest/db/browse?folder=j663y-3ct3e&prefix=DCIM&levels=2
[

    {

        "modTime" : "2020-10-02T23:48:52.076996974+02:00",

        "name" : "100ANDRO",

        "size" : 128,

        "type" : "FILE_INFO_TYPE_DIRECTORY"

    },

    {

        "children" : [

            {

                "modTime" : "2020-12-16T23:31:34.5009668+01:00",

                "name" : "IMG_20201114_124821.jpg",

                "size" : 10682189,

                "type" : "FILE_INFO_TYPE_FILE"

            },

            {

                "modTime" : "2020-12-16T23:31:35.0106367+01:00",

                "name" : "IMG_20201213_122451.jpg",

                "size" : 7936351,

                "type" : "FILE_INFO_TYPE_FILE"

            },

            {

                "modTime" : "2020-12-13T12:25:05.017097469+01:00",

                "name" : "IMG_20201213_122504.jpg",

                "size" : 8406507,

                "type" : "FILE_INFO_TYPE_FILE"

            },

            {

                "modTime" : "2020-12-13T12:25:06.127097469+01:00",

                "name" : "IMG_20201213_122505.jpg",

                "size" : 8381931,

                "type" : "FILE_INFO_TYPE_FILE"

            },

            {

                "modTime" : "2020-12-13T12:53:29.707298401+01:00",

                "name" : "IMG_20201213_125329.jpg",

                "size" : 4388331,

                "type" : "FILE_INFO_TYPE_FILE"

            },

        ],

        "modTime" : "2020-10-09T13:04:42.4410738+02:00",

        "name" : "Camera",

        "size" : 128,

        "type" : "FILE_INFO_TYPE_DIRECTORY"

    },
]
```

NOTE:

This is an expensive call, increasing CPU and RAM usage on the device. Use sparingly.

### GET /rest/db/completion
Returns the completion percentage (0 to 100) and byte / item counts. Takes optional device and folder parameters:

- folder specifies the folder ID to calculate completion for. An empty or absent folder parameter means all folders as an aggregate.

- device specifies the device ID to calculate completion for. An empty or absent device parameter means the local device.

If a device is specified but no folder, completion is calculated for all folders shared with that device.

### Example Queries
Completion status for folder abcd-1234 on device I6KAH76-...-3PSROAU:

```
/rest/db/completion?folder=abcd-1234&device=I6KAH76-...-3PSROAU
```

Aggregated completion status for device I6KAH76-...-3PSROAU (all folders shared with them):

```
/rest/db/completion?device=I6KAH76-...-3PSROAU
```

Completion status for folder abcd-1234 on the local device:

```
/rest/db/completion?folder=abcd-1234
```

Aggregated completion status for all folders on the local device:

```
/rest/db/completion
```

### Example Response

```
{

  "completion": 99.9937565835,

  "globalBytes": 156793013575,

  "needBytes": 9789241,

  "globalItems": 7823,

  "needItems": 412,

  "needDeletes": 0,

  "remoteState": "valid",

  "sequence": 12
}
```

Added in version 1.8.0: The ability to aggregate multiple folders by leaving out the folder ID. Querying data for the local device by leaving out the device ID. Returning the globalItems counter in the response.

Added in version 1.20.0: Indication whether the remote device has accepted the folder (shares it with us) as well, and whether it is paused. The remoteState field is meaningless for aggregated responses, unknown when the remote device is not connected. Otherwise it can be either paused, notSharing, or valid if the remote is sharing back.

### GET /rest/db/file
Returns most data about a given file, including version and availability.

### Request
The call requires parameters for folder and file in the query string:

- folder is the folder ID which you can find in the Syncthing Web GUI, e.g. 5camp-slpa8.

- file is the relative path of the file starting from the folder root to the file you are interested in. The path and filename must be correctly URL-encoded.

### Example Request

```
$ curl -s -H X-API-KEY:... "http://localhost:8384/rest/db/file?folder=YOUR_FOLDER_ID" --url-query "file=path/to/file.pdf"
```

### Response

```
{

  "availability": [

    {

      "id": "ITZRNXE-YNROGBZ-HXTH5P7-VK5NYE5-QHRQGE2-7JQ6VNJ-KZUEDIU-5PPR5AM",

      "fromTemporary": false

    }

  ],

  "global": { /* a file entry */ },

  "local": { /* a file entry */ },

  "mtime": {

    "err": null,

    "value": {

      "real": "0001-01-01T00:00:00Z",

      "virtual": "0001-01-01T00:00:00Z"

  }
}
```

local and global refer to the current file on the local device and the globally newest file, respectively. A file entry looks like this:

```
{

  "deleted": false,

  "ignored": false,

  "inodeChange": "1970-01-01T01:00:00+01:00",

  "invalid": false,

  "localFlags": 0,

  "modified": "2022-09-28T08:07:19.979723+02:00",

  "modifiedBy": "523ITIE",

  "mustRescan": false,

  "name": "img",

  "noPermissions": false,

  "numBlocks": 0,

  "permissions": "0755",

  "platform": { /* platform specific data */ },

  "sequence": 914,

  "size": 128,

  "type": "FILE_INFO_TYPE_DIRECTORY",

  "version": [

    "523ITIE:1664345275"

  ]
}
```

Platform specific data may be ownership, extended attributes, etc. and is divided into entries per operating system / platform. An example platform entry containing ownership information for Unix systems and an extended attribute for macOS (“darwin”) looks as follows:

```
{

  "darwin": {

    "xattrs": [

      {

        "name": "net.kastelo.xattrtest",

        "value": "aGVsbG8="

      }

    ]

  },

  "freebsd": null,

  "linux": null,

  "netbsd": null,

  "unix": {

    "gid": 20,

    "groupName": "staff",

    "ownerName": "jb",

    "uid": 501

  },

  "windows": null
}
```

### GET /rest/db/ignores
Takes one parameter, folder, and returns the content of the .stignore as the ignore field. A second field, expanded, provides a list of strings which represent globbing patterns described by gobwas/glob (based on standard wildcards) that match the patterns in .stignore and all the includes. If appropriate these globs are prepended by the following modifiers: ! to negate the glob, (?i) to do case insensitive matching and (?d) to enable removing of ignored files in an otherwise empty directory.

```
{

  "ignore": [

    "(?i)/Backups"

  ],

  "expanded": [

    "(?i)Backups",

    "(?i)Backups/**"

  ]
}
```

### POST /rest/db/ignores
Expects a format similar to the output of GET /rest/db/ignores call, but only containing the ignore field (expanded field should be omitted). It takes one parameter, folder, and either updates the content of the .stignore echoing it back as a response, or returns an error.

### GET /rest/db/localchanged
Added in version 0.14.55.

Takes one mandatory parameter, folder, and returns the list of files which were changed locally in a receive-only folder. Thus they differ from the global state and could be reverted by pulling from remote devices again, see POST /rest/db/revert.

The results can be paginated using the common pagination parameters.

```
{

  "files": [

    {

      "flags": "0755",

      "sequence": 6,

      "modified": "2015-04-20T23:06:12+09:00",

      "name": "ls",

      "size": 34640,

      "version": [

        "5157751870738175669:1"

      ]

    }

  ],

  "page": 1,

  "perpage": 100
}
```

NOTE:

This is an expensive call, increasing CPU and RAM usage on the device. Use sparingly.

### GET /rest/db/need
Takes one mandatory parameter, folder, and returns lists of files which are needed by this device in order for it to become in sync.

The results can be paginated using the common pagination parameters. Pagination happens, across the union of all needed files, that is - across all 3 sections of the response. For example, given the current need state is as follows:

1.

progress has 15 items

2.

queued has 3 items

3.

rest has 12 items

If you issue a query with page=1 and perpage=10, only the progress section in the response will have 10 items. If you issue a request query with page=2 and perpage=10, progress section will have the last 5 items, queued section will have all 3 items, and rest section will have first 2 items. If you issue a query for page=3 and perpage=10, you will only have the last 10 items of the rest section.

NOTE:

Return format changed in version 0.14.43, removing the total count attribute.

```
{

  # Files currently being downloaded

  "progress": [

    {

      "flags": "0755",

      "sequence": 6,

      "modified": "2015-04-20T23:06:12+09:00",

      "name": "ls",

      "size": 34640,

      "version": [

        "5157751870738175669:1"

      ]

    }

  ],

  # Files queued to be downloaded next (as per array order)

  "queued": [

      ...

  ],

  # Files to be downloaded after all queued files will be downloaded.

  # This happens when we start downloading files, and new files get added while we are downloading.

  "rest": [

      ...

  ],

  "page": 1,

  "perpage": 100
}
```

NOTE:

This is an expensive call, increasing CPU and RAM usage on the device. Use sparingly.

### POST /rest/db/override
Request override of a send only folder. Override means to make the local version latest, overriding changes made on other devices. This API call does nothing if the folder is not a send only folder.

Takes the mandatory parameter folder (folder ID).

```
curl -X POST -H X-API-key:... http://127.0.0.1:8384/rest/db/override?folder=default
```

### POST /rest/db/prio
Moves the file to the top of the download queue.

```
curl -X POST http://127.0.0.1:8384/rest/db/prio?folder=default&file=foo/bar
```

Response contains the same output as GET /rest/db/need.

### GET /rest/db/remoteneed
Added in version 0.14.43.

Takes the mandatory parameters folder and device, and returns the list of files which are needed by that remote device in order for it to become in sync with the shared folder.

The results can be paginated using the common pagination parameters.

```
{

  "files": [

    {

      "flags": "0755",

      "sequence": 6,

      "modified": "2015-04-20T23:06:12+09:00",

      "name": "ls",

      "size": 34640,

      "version": [

        "5157751870738175669:1"

      ]

    }

  ],

  "page": 1,

  "perpage": 100
}
```

NOTE:

This is an expensive call, increasing CPU and RAM usage on the device. Use sparingly.

### POST /rest/db/revert
Added in version 0.14.50.

Request revert of a receive only folder. Reverting a folder means to undo all local changes. This API call does nothing if the folder is not a receive only folder.

Takes the mandatory parameter folder (folder ID).

```
curl -X POST -H X-API-Key:... http://127.0.0.1:8384/rest/db/revert?folder=default
```

### POST /rest/db/scan
Request immediate scan. Takes the optional parameters folder (folder ID), sub (path relative to the folder root) and next (time in seconds). If folder is omitted or empty all folders are scanned. If sub is given, only this path (and children, in case it’s a directory) is scanned. The next argument delays Syncthing’s automated rescan interval for a given amount of seconds.

Requesting scan of a path that no longer exists, but previously did, is valid and will result in Syncthing noticing the deletion of the path in question.

Returns status 200 and no content upon success, or status 500 and a plain text error if an error occurred during scanning.

```
curl -X POST http://127.0.0.1:8384/rest/db/scan?folder=default&sub=foo/bar
```

### GET /rest/db/status
Returns information about the current status of a folder.

Parameters: folder, the ID of a folder.

```
{

  "globalBytes": 0,

  "globalDeleted": 0,

  "globalDirectories": 0,

  "globalFiles": 0,

  "globalSymlinks": 0,

  "globalTotalItems": 0,

  "ignorePatterns": false,

  "inSyncBytes": 0,

  "inSyncFiles": 0,

  "invalid": "",

  "localBytes": 0,

  "localDeleted": 0,

  "localDirectories": 0,

  "localFiles": 0,

  "localSymlinks": 0,

  "localTotalItems": 0,

  "needBytes": 0,

  "needDeletes": 0,

  "needDirectories": 0,

  "needFiles": 0,

  "needSymlinks": 0,

  "needTotalItems": 0,

  "pullErrors": 0,

  "receiveOnlyChangedBytes": 0,

  "receiveOnlyChangedDeletes": 0,

  "receiveOnlyChangedDirectories": 0,

  "receiveOnlyChangedFiles": 0,

  "receiveOnlyChangedSymlinks": 0,

  "receiveOnlyTotalItems": 0,

  "sequence": 0,

  "state": "idle",

  "stateChanged": "2018-08-08T07:04:57.301064781+02:00",

  "version": 0
}
```

The various fields have the following meaning:

global*:

Data in the cluster latest version.

inSync*:

Data that is locally the same as the cluster latest version.

local*:

Data that is locally present, regardless of whether it’s the same or different version as the cluster latest version.

need*:

Data that is needed to become up to date with the cluster latest version (i.e., data that is out of sync).

receiveOnlyChanged*:

Data that has changed locally in a receive only folder, and thus not been sent to the cluster.

invalid:

Deprecated, always empty.

pullErrors:

The number of files that failed to sync during the last sync operations.

sequence:

The current folder sequence number.

state:

The current folder state.

stateChanged:

When the folder state last changed.

version:

Deprecated, equivalent to the sequence number.

NOTE:

This is an expensive call, increasing CPU and RAM usage on the device. Use sparingly.

## EVENT ENDPOINTS

### GET /rest/events
To receive events, perform a HTTP GET of /rest/events.

To filter the event list, in effect creating a specific subscription for only the desired event types, add a parameter events=EventTypeA,EventTypeB,... where the event types are any of the Event Types. If no filter is specified, all events except LocalChangeDetected and RemoteChangeDetected are included.

The optional parameter since=<lastSeenID> sets the ID of the last event you’ve already seen. Syncthing returns a JSON encoded array of event objects, starting at the event just after the one with this last seen ID. The default value is 0, which returns all events. There is a limit to the number of events buffered, so if the rate of events is high or the time between polling calls is long some events might be missed. This can be detected by noting a discontinuity in the event IDs.

If no new events are produced since <lastSeenID>, the HTTP call blocks and waits for new events to happen before returning. If <lastSeenID> is a future ID, the HTTP call blocks until such ID is reached or timeouts. By default it times out after 60 seconds returning an empty array. The time out duration can be customized with the optional parameter timeout=<seconds>.

To receive only a limited number of events, add the limit=<n> parameter with a suitable value for n and only the last n events will be returned. This can be used to catch up with the latest event ID after a disconnection for example: /rest/events?since=0&limit=1.

### GET /rest/events/disk
This convenience endpoint provides the same event stream, but pre-filtered to show only LocalChangeDetected and RemoteChangeDetected event types. The events parameter is not used.

## STATISTICS ENDPOINTS

### GET /rest/stats/device
Returns general statistics about devices. Currently, only contains the time the device was last seen and the last connection duration.

```
$ curl -s http://localhost:8384/rest/stats/device | json
{

  "P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2": {

    "lastSeen" : "2015-04-18T11:21:31.3256277+01:00"

    "lastConnectionDurationS": 556335.421708141

  }
}
```

### GET /rest/stats/folder
Returns general statistics about folders. Currently contains the last scan time and the last synced file.

```
{

  "folderid": {

    "lastScan": "2016-06-02T13:28:01.288181412-04:00",

    "lastFile": {

      "filename": "file/name",

      "at": "2015-04-16T22:04:18.3066971+01:00"

    }

  }
}
```

## MISC SERVICES ENDPOINTS

### GET /rest/svc/deviceid
Verifies and formats a device ID. Accepts all currently valid formats (52 or 56 characters with or without separators, upper or lower case, with trivial substitutions). Takes one parameter, id, and returns either a valid device ID in modern format, or an error.

```
$ curl -s http://localhost:8384/rest/svc/deviceid?id=1234 | json
{

  "error": "device ID invalid: incorrect length"
}
$ curl -s http://localhost:8384/rest/svc/deviceid?id=p56ioi7m--zjnu2iq-gdr-eydm-2mgtmgl3bxnpq6w5btbbz4tjxzwicq | json
{

  "id": "P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2"
}
```

### GET /rest/svc/lang
Returns a list of canonicalized localization codes, as picked up from the Accept-Language header sent by the browser.

```
["sv_sv","sv","en_us","en"]
```

### GET /rest/svc/random/string
Returns a strong random generated string (alphanumeric) of the specified length. Takes the length parameter.

```
{

  "random": "FdPaEaZQ56sXEKYNxpgF"
}
```

### GET /rest/svc/report
Returns the data sent in the anonymous usage report.

```
{

   "folderMaxMiB" : 0,

   "platform" : "linux-amd64",

   "totMiB" : 0,

   "longVersion" : "syncthing v0.12.2 \"Beryllium Bedbug\" (go1.4.3 linux-amd64 default) unknown-user@build2.syncthing.net 2015-11-09 13:23:26 UTC",

   "upgradeAllowedManual" : true,

   "totFiles" : 3,

   "folderUses" : {

      "ignorePerms" : 0,

      "autoNormalize" : 0,

      "sendonly" : 0,

      "ignoreDelete" : 0

   },

   "memoryUsageMiB" : 13,

   "version" : "v0.12.2",

   "sha256Perf" : 27.28,

   "numFolders" : 2,

   "memorySize" : 1992,

   "announce" : {

      "defaultServersIP" : 0,

      "otherServers" : 0,

      "globalEnabled" : false,

      "defaultServersDNS" : 1,

      "localEnabled" : false

   },

   "usesRateLimit" : false,

   "numCPU" : 2,

   "uniqueID" : "",

   "urVersion" : 2,

   "rescanIntvs" : [

      60,

      60

   ],

   "numDevices" : 2,

   "folderMaxFiles" : 3,

   "relays" : {

      "defaultServers" : 1,

      "enabled" : true,

      "otherServers" : 0

   },

   "deviceUses" : {

      "compressMetadata" : 1,

      "customCertName" : 0,

      "staticAddr" : 1,

      "compressAlways" : 0,

      "compressNever" : 1,

      "introducer" : 0,

      "dynamicAddr" : 1

   },

   "upgradeAllowedAuto" : false
}
```

## DEBUG ENDPOINTS

### GET /rest/debug/cpuprof
Used to capture a profile of what Syncthing is doing on the CPU. See Profiling.

### GET /rest/debug/heapprof
Used to capture a profile of what Syncthing is doing with the heap memory. See Profiling.

### GET /rest/debug/support
Collects information about the running instance for troubleshooting purposes. Returns a “support bundle” as a zipped archive, which should be sent to the developers after verifying it contains no sensitive personal information. Credentials for the web GUI and the API key are automatically redacted already.

### GET /rest/debug/file
Shows diagnostics about a certain file in a shared folder. Takes the folder (folder ID) and file (folder relative path) parameters.

```
$ curl -H X-API-Key:... "http://localhost:8384/rest/debug/file?folder=default&file=foo/bar"
```

The returned object contains the same info as GET /rest/db/file, plus a summary of globalVersions.

## NOAUTH ENDPOINTS
Calls that do not require authentication.

### GET /rest/noauth/health
Returns a {"status": "OK"} object.

```
{

  "status": "OK"
}
```

## AUTHOR
The Syncthing Authors

## COPYRIGHT
2014-2026, The Syncthing Authors


syncthing-security

package: syncthing

title: syncthing-security(7)

summary: Security Principles

text:
# syncthing-security(7)

## NAME
syncthing-security - Security Principles

Security is one of the primary project goals. This means that it should not be possible for an attacker to join a cluster uninvited, and it should not be possible to extract private information from intercepted traffic. Currently this is implemented as follows.

All device to device traffic is protected by TLS. To prevent uninvited devices from joining a cluster, the certificate fingerprint of each device is compared to a preset list of acceptable devices at connection establishment. The fingerprint is computed as the SHA-256 hash of the certificate and displayed in a human-friendly encoding, called Device ID.

Incoming requests for file data are verified to the extent that the requested file name must exist in the local index and the global model.

For information about ensuring you are running the code you think you are and for reporting security vulnerabilities, please see the official security page <https://syncthing.net/security>.

## INFORMATION LEAKAGE

### Global Discovery
When global discovery is enabled, Syncthing sends an announcement every 30 minutes to the global discovery servers so that they can keep a mapping between your device ID and external IP. The announcement contain the device ID and listening port(s). Also, when connecting to other devices that have not been seen on the local network, a query is sent to the global discovery servers containing the device ID of the requested device. The connection to the discovery server is encrypted using TLS and the discovery server certificate is verified, so the contents of the query should be considered private between the device and the discovery server. The discovery servers are currently hosted by @calmh <https://github.com/calmh>. Global discovery defaults to on.

When turned off, devices with dynamic addresses not on the local network cannot be found and connected to.

An eavesdropper on the Internet can deduce which machines are running Syncthing with global discovery enabled, and what their device IDs are.

The operator of the discovery server can map arbitrary device addresses to IP addresses, and deduce which devices are connected to each other.

If a different global discovery server is configured, no data is sent to the default global discovery servers.

### Local Discovery
When local discovery is enabled, Syncthing sends broadcast (IPv4) and multicast (IPv6) packets to the local network every 30 seconds. The packets contain the device ID and listening port. Local discovery defaults to on.

An eavesdropper on the local network can deduce which machines are running Syncthing with local discovery enabled, and what their device IDs are.

When turned off, devices with dynamic addresses on the local network cannot be found and connected to.

### Upgrade Checks
When automatic upgrades are enabled, Syncthing checks for a new version at startup and then once every twelve hours. This is by an HTTPS request to the download site for releases, currently hosted by @calmh <https://github.com/calmh>. Automatic upgrades default to on (unless Syncthing was compiled with upgrades disabled).

Even when automatic upgrades are disabled in the configuration, an upgrade check as above is done when the GUI is loaded, in order to show the “Upgrade to …” button when necessary. This can be disabled only by compiling Syncthing with upgrades disabled.

The actual download, should an upgrade be available, is done from GitHub, thus exposing the user to them.

The upgrade check (or download) requests do not contain any identifiable information about the user or device.

### Usage Reporting
When usage reporting is enabled, Syncthing reports usage data at startup and then every 24 hours. The report is sent as an HTTPS POST to the usage reporting server, currently hosted by @calmh <https://github.com/calmh>. The contents of the usage report can be seen behind the “Preview” link in settings. Usage reporting defaults to off but the GUI will ask once about enabling it, shortly after the first install.

The reported data is protected from eavesdroppers, but the connection to the usage reporting server itself may expose the client as running Syncthing.

### Sync Connections (BEP)
Sync connections are attempted to all configured devices, when the address is possible to resolve. The sync connection is based on TLS 1.2 or TLS 1.3. The TLS certificates can be obtained by an eavesdropper, although it is more difficult to do so in TLS 1.3. This means that the contents of the certificate are visible, which includes certificate Common Name (by default syncthing).

An eavesdropper can deduce that this is a Syncthing connection and under certain circumstances calculate the device IDs involved based on the hashes of the sent certificates.

Likewise, if the sync port (default 22000) is accessible from the internet, a port scanner may discover it, attempt a TLS negotiation and thus obtain the device certificate. This provides the same information as in the eavesdropper case.

### Relay Connections
When relaying is enabled, Syncthing will look up the pool of public relays and establish a connection to one of them (the best, based on an internal heuristic). The selected relay server will learn the connecting device’s device ID. Relay servers can be run by anyone in the general public. Relaying defaults to on. Syncthing can be configured to disable relaying, or only use specific relays.

If a relay connections is required between two devices, the relay will learn the other device’s device ID as well.

Any data exchanged between the two devices is encrypted as usual and not subject to inspection by the relay.

### Web GUI
If the web GUI is accessible, it exposes the device as running Syncthing. The web GUI defaults to being reachable from the local host only.

## IN SHORT
Parties doing surveillance on your network (whether that be corporate IT, the NSA or someone else) will be able to see that you use Syncthing, and your device IDs are OK to share anyway <https://docs.syncthing.net/users/faq.html#should-i-keep-my-device-ids-secret>, but the actual transmitted data is protected as well as we can. Knowing your device ID can expose your IP address, using global discovery.

## PROTECTING YOUR SYNCTHING KEYS AND IDENTITY
Anyone who can access the Syncthing TLS keys and config file on your device can impersonate your device, connect to your peers, and then have access to your synced files. Here are some general principles to protect your files:

1.

If a device of yours is lost, make sure to revoke its access from your other devices.

2.

If you’re syncing confidential data on an encrypted disk to guard against device theft, put the Syncthing config folder on the same encrypted disk to avoid leaking keys and metadata. Or, use whole disk encryption.

## AUTHOR
The Syncthing Authors

## COPYRIGHT
2014-2026, The Syncthing Authors

branch: sisyphus


syncthing-versioning

title: syncthing-versioning(7)

text:
# syncthing-versioning(7)

## NAME
syncthing-versioning - Keep automatic backups of deleted files by other nodes

Syncthing supports archiving the old version of a file when it is deleted or replaced with a newer version from the cluster. This is called “file versioning” and uses one of the available versioning strategies described below. File versioning is configured per folder, on a per-device basis, and defaults to “no file versioning”, i.e. no old copies of files are kept.

NOTE:

Versioning applies to changes received from other devices. That is, if Alice has versioning turned on and Bob changes a file, the old version will be archived on Alice’s computer when that change is synced from Bob. If Alice changes a file locally on her own computer Syncthing will not and can not archive the old version.

The applicable configuration options for each versioning strategy are described below. For most of them it’s possible to specify where the versions are stored, with the default being the .stversions folder inside the shared folder path. If you set a custom version path, please ensure that it’s on the same partition or filesystem as the regular folder path, as moving files there may otherwise fail.

## TRASH CAN FILE VERSIONING
This versioning strategy emulates the common “trash can” approach. When a file is deleted or replaced due to a change on a remote device, it is moved to the trash can in the .stversions folder. If a file with the same name was already in the trash can it is replaced.

A configuration option is available to clean the trash can from files older than a specified number of days. If this is set to a positive number of days, files will be removed when they have been in the trash can that long. Setting this to zero prevents any files from being removed from the trash can automatically.

## SIMPLE FILE VERSIONING
With “Simple File Versioning” files are moved to the .stversions folder when replaced or deleted on a remote device. In addition to the cleanoutDays option, this strategy also takes a value in an input titled “Keep Versions” which tells Syncthing how many old versions of the file it should keep. For example, if you set this value to 5, if a file is replaced 5 times on a remote device, you will see 5 time-stamped versions on that file in the .stversions folder on the other devices sharing the same folder.

## STAGGERED FILE VERSIONING
With “Staggered File Versioning” files are also moved to the .stversions folder when replaced or deleted on a remote device (just like “Simple File Versioning”), however, versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.

The following intervals are used and they each have a maximum number of files that will be kept for each.

1 Hour

For the first hour, the oldest version in every 30-seconds interval is kept.

1 Day

For the first day, the oldest version in every hour is kept.

30 Days

For the first 30 days, the oldest version in every day is kept.

Until Maximum Age

Until maximum age, the oldest version in every week is kept.

Maximum Age

The maximum time to keep a version in days. For example, to keep replaced or deleted files in the .stversions folder for an entire year, use 365. If only for 10 days, use 10. Corresponds to the maxAge option. Note: Set to 0 to keep versions forever.

This means that there is only one version in each interval and as files age they will be deleted unless when the interval they are entering is empty. By keeping the oldest versions this versioning scheme preserves the file if it is overwritten.

For more info, check the unit test file <https://github.com/syncthing/syncthing/blob/main/lib/versioner/staggered_test.go#L32> that shows which versions are deleted for a specific run.

## EXTERNAL FILE VERSIONING
This versioning strategy delegates the decision on what to do to an external command (e.g. a program or a command line script). Just prior to a file being replaced, the command will be executed. The file needs to be removed from the folder in the process, or otherwise Syncthing will report an error. The command can use the following templated arguments:

%FOLDER_PATH%

Path to the folder

%FILE_PATH%

Path to the file within the folder

Note that the former expands to the path of the actual Syncthing folder, and the latter to the path inside that folder. For instance, if you use the default Sync folder in Windows, and the full path to the file is C:\Users\User\Sync\Family photos\IMG_2021-03-01.jpg, then the %FOLDER_PATH% will be C:\Users\User\Sync, and the %FILE_PATH% will be Family photos\IMG_2021-03-01.jpg.

### Example for Unixes
Let’s say I want to keep the latest version of each file as they are replaced or removed; essentially I want a “trash can”-like behavior. For this, I create the following script and store it as /Users/jb/bin/onlylatest.sh (i.e. the bin directory in my home directory):

```
#!/bin/sh
set -eu
# Where I want my versions stored
versionspath=~/.trashcan
# The parameters we get from Syncthing
folderpath="$1"
filepath="$2"
# First ensure the dir where we need to store the file exists
outpath=$(dirname "$versionspath/$filepath")
mkdir -p "$outpath"
# Then move the file there
mv -f "$folderpath/$filepath" "$versionspath/$filepath"
```

I must ensure that the script has execute permissions (chmod 755 onlylatest.sh), then configure Syncthing with command /Users/jb/bin/onlylatest.sh %FOLDER_PATH% %FILE_PATH%

Let’s assume I have a folder “default” in ~/Sync, and that within that folder there is a file docs/letter.txt that is being replaced or deleted. The script will be called as if I ran this from the command line:

```
$ /Users/jb/bin/onlylatest.sh /Users/jb/Sync docs/letter.txt
```

The script will then move the file in question to ~/.trashcan/docs/letter.txt, replacing any previous version of that letter that may already have been there.

### Move to a given folder using the command prompt (CMD)
On Windows we can use a batch script to perform the same “trash can”-like behavior as mentioned above. I created the following script and saved it as C:\Users\mfrnd\Scripts\onlylatest.bat.

```
@echo off
rem Enable UTF-8 encoding to deal with multilingual folder and file names
chcp 65001
rem We need command extensions for md to create intermediate folders in one go
setlocal enableextensions
rem Where I want my versions stored
set "versions_path=%USERPROFILE%\.trashcan"
rem The parameters we get from Syncthing, '~' removes quotes if any
set "folder_path=%~1"
set "file_path=%~2"
rem First ensure the dir where we need to store the file exists
for %%f in ("%versions_path%\%file_path%") do set "output_path=%%~dpf"
if not exist "%output_path%" md "%output_path%" || exit /b
rem Finally move the file, overwrite existing file if any
move /y "%folder_path%\%file_path%" "%versions_path%\%file_path%"
```

Finally, I set "C:\Users\mfrnd\Scripts\onlylatest.bat" "%FOLDER_PATH%" "%FILE_PATH%" as the command name in Syncthing.

### Move to the Recycle Bin using PowerShell
We can use PowerShell to send files directly to the Recycle Bin, which mimics the behaviour of deleting them using the Windows Explorer. Firstly, create the following script and save it in your preferred location, e.g. C:\Users\User\Scripts\SendToRecycleBin.ps1.

```
# PowerShell has no native method to recycle files, so we use Visual
# Basic to perform the operation. If succeeded, we also include the
# recycled file in the Syncthing's DEBUG output.
Add-Type -AssemblyName Microsoft.VisualBasic
[Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile($args,'OnlyErrorDialogs','SendToRecycleBin')
if ($?) {

  Write-Output ("Recycled " + $args + ".")
}
```

Alternatively, the script can be expanded to send only deleted files to the Recycle Bin, and permanently delete modified ones, which makes it more consistent with how the Explorer works.

```
# PowerShell has no native method to recycle files, so we use Visual
# Basic to perform the operation.
Add-Type -AssemblyName Microsoft.VisualBasic
# We need to test if a Syncthing .tmp file exists. If it does, we assume
# a modification and delete the existing file. If if does not, we assume
# a deletion and recycle the current file. If succeeded, we also include
# the deleted/recycled file in the Syncthing's DEBUG output.
if (Test-Path -LiteralPath ((Split-Path -Path $args) + "\~syncthing~" + (Split-Path -Path $args -Leaf) + ".tmp")) {

  [Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile($args,'OnlyErrorDialogs','DeletePermanently')

  if ($?) {

    Write-Output ("Deleted " + $args + ".")

  }
} else {

  [Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile($args,'OnlyErrorDialogs','SendToRecycleBin')

  if ($?) {

    Write-Output ("Recycled " + $args + ".")

  }
}
```

Finally, we set the command name in Syncthing to powershell.exe -ExecutionPolicy Bypass -File "C:\Users\User\Scripts\SendToRecycleBin.ps1" "%FOLDER_PATH%\%FILE_PATH%".

The only caveat that you should be aware of is that if your Syncthing folder is located on a portable storage, such as a USB stick, or if you have the Recycle Bin disabled, then the script will end up deleting all files permanently.

## CONFIGURATION PARAMETER REFERENCE
The versioning settings are grouped into their own section of each folder in the configuration file. The following shows an example of such a section in the XML:

```
<folder id="...">

    <versioning type="simple">

        <cleanupIntervalS>3600</cleanupIntervalS>

        <fsPath></fsPath>

        <fsType>basic</fsType>

        <param key="cleanoutDays" val="0"></param>

        <param key="keep" val="5"></param>

    </versioning>
</folder>
```

versioning.type

Selects one of the versioning strategies: trashcan, simple, staggered, external or leave empty to disable versioning completely.

versioning.fsPath

Overrides the path where old versions of files are stored and defaults to .stversions if left empty. An absolute or relative path can be specified. The latter is interpreted relative to the shared folder path, if the fsType is configured as basic. Ignored for the external versioning strategy. This option used to be stored under the keys fsPath or versionsPath in the params element.

versioning.fsType

The internal file system implementation used to access this versions folder. Only applies if fsPath is also set non-empty, otherwise the filesystemType from the folder element is used instead. Refer to that option description for possible values. Ignored for the external versioning strategy. This option used to be stored under the key fsType in the params element.

versioning.cleanupIntervalS

The interval, in seconds, for running cleanup in the versions folder. Zero to disable periodic cleaning. Limited to one year (31536000 seconds). Ignored for the external versioning strategy. This option used to be stored under the key cleanInterval in the params element.

versioning.params

Each versioning strategy can have configuration parameters specific to its implementation under this element.

versioning.params.cleanoutDays

The number of days to keep files in the versions folder. Zero means to keep forever. Older elements encountered during cleanup are removed.

versioning.params.keep

The number of old versions to keep, per file.

versioning.params.maxAge

The maximum time to keep a version, in seconds. Zero means to keep forever.

versioning.params.command

External command to execute for storing a file version about to be replaced or deleted. If the path to the application contains spaces, it should be quoted.

## AUTHOR
The Syncthing Authors

## COPYRIGHT
2014-2026, The Syncthing Authors


sysconftool

package: sysconftool

title: sysconftool(7)

text:
# sysconftool(7)

## NAME
sysconftool - format of configuration files installed by sysconftool

## SYNOPSIS

```
   #

   ##VERSION: $Id$

   ##NAME: configname1:configname1version

   #

   # Description

   SETTING1=VALUE1

   ##NAME: configname2:configname2version

   #

   # Description

   SETTING2=VALUE2

   ...
```

## DESCRIPTION
This manual page describes the format of configuration files installed by sysconftool(1)[1]. This format is flexible enough to accomodate any kind of application configuration file format. sysconftool makes four assumptions about the configuration file:

1.It is a plain text file.

2.Lines that begin with a single '#' character are comments that contain a description of the following configuration setting.

3.Lines that do not begin with the '#' character contain the configuration setting described by the previous comment lines.

4.Configuration settings are self contained, and completely independent, changing one configuration setting never requires that another, different, configuration setting must be changed too (perhaps any logical conflicts are automatically resolved by the application in a safe, fallback, manner)

The additional information used by sysconftool is encoded as specially-formatted comment lines that begin with two '#' characters.

## FILENAMES
An application installs a default configuration file as "filename.dist", when the actual name of the configuration file is really "filename". If there is no existing filename, sysconftool simply copies filename.dist to filename, and calls it a day. Otherwise, sysconftool copies the existing filename to filename.bak and creates a new filename based on the contents of both files.

sysconftool is designed to solve a common problem with application configuration. New versions of applications often include additional functionality that requires new configuration settings. Without the new configuration settings the application will not work, so new configuration files should be installed during the upgrade. However, when that happens, any changes to the existing configuration settings are lost. sysconftool is designed to solve this dillemma, and merge old configuration settings with new ones. sysconftool is designed in a fail-safe way. Whenever there's a doubt as to what's The Right Thing To Do, sysconftool will use the configuration settings from the new file, that are supposedly known to be good, and leave it up to a physical being to sort out any conflicts and make any manual decisions.

## FILE VERSIONING
The following line should appear at the beginning of filename.dist:

```
   ##VERSION: version
```

This doesn't have to be the very first line in filename.dist, but it should appear somewhere within the first twenty lines, right before the first configuration setting. "version" should be some kind of an identifier for this particular version of the configuration files. All that sysconftool cares about is that any change to the default configuration, in filename.dist, results in a different version. An excellent way to do this is to simply use the $Id$ RCS/CVS version identification strings, and have this little detail taken care of automatically.

New revisions of an application should not necessarily have a new configuration file version. If the default application configuration settings have not changed from the previous release, version can remain the same. version is copied from filename.dist to filename.

If there's an existing filename, and it includes the same version identifier, sysconftool silently skips over this configuration file, and doesn't do anything, assuming that this configuration file has already been installed. Therefore, running sysconftool more than once (accidentally) will not break anything.

If there's an existing filename, but it's version is different, sysconftool backs it up to filename.bak, then creates a new filename. If there's an existing filename, but it doesn't contain a recognizable "##VERSION: version" line, sysconftool assumes that the previous version of the application did not use the sysconftool tool. That's not a problem. filename is copied to filename.bak, and filename.dist gets installed as the new filename, allowing sysconftool to work with the next version of this configuration file.

## CONFIGURATION SETTING VERSIONING
Each configuration setting uses the following format in the configuration file:

```
   ##NAME: name:revision

   #

   # description

   setting
```

sysconftool looks for a line that begins with "##NAME". This line gives the name and the revision of the following setting. name must be unique within its configuration file (the same name can be used by different configuration files, sysconftool works with one file at a time). revision is used by sysconftool to decide when the configuration setting can be safely carried over from an older configuration file, and when it is better to reinstall the default setting from the new configuration file.

One or more comment lines - lines that begin with the '#' character - may follow "##NAME". The first line that does not begin with '#' is considered to be the first line that contains the value of the configuration setting, which lasts. The value can be spread over multiple lines. The configuration setting is considered to last until either the end of the file, or until the first following line that begins with another "##NAME".

Aside from that, sysconftool does not care how the configuration setting is represented. It can be "NAME=VALUE", it can be "NAME: VALUE", or "NAME<tab>VALUE", it can even be a base64-encoded binary object, and it can always have leading or trailing blank lines. sysconftool merely looks at which lines begin with the '#' comment character. After the '##NAME:' line, sysconftool looks ahead until the first line that does not begin with '#', and that's the first line of the configuration setting. Then, sysconftool looks ahead until the next line that starts with a "##NAME:", which marks the end of this configuration setting.

For this reason it is important that all commented description lines that follow '##NAME:' must begin with the '#' character. If a blank line follows the line with '##NAME:' it is assumed to be the start of the corresponding configuration setting. For example, this is correct:

```
   ##NAME: flag1:0

   #

   #

   # This is the first configuration flag

   #

   flag1=1
```

This is not correct:

```
   ##NAME: flag1:0

   #

   # This is the first configuration flag

   #

   flag1=1
```

## CONFIGURATION FILE CREATION
A new configuration file, "filename", is created from its previous version, "filename.bak" and the new default configuration file, "filename.dist", using the following, simple, two-step process.

1.sysconftool begins with filename.dist in hand. This makes sure that sysconftool begins with a good, known, default configuration file.

2.sysconftool then takes each configuration setting in filename.dist, then searches filename.bak. If it finds a configuration setting that has an identical "name" and "version", then the corresponding configuration setting value is taken from filename.bak, replacing the default in filename.dist. After all configuration settings in filename.dist are looked up (and potentially replaced), what's left becomes the new filename.

## THE END RESULT
The above process is a logical description. The actual technical implementation is slightly different (for example, filename is not backed up to filename.bak until the new configuration file has been already created), but is logically equivalent to this process. This process carries a number of consequences that must be considered.

If a new application revision needs a new configuration setting, it will get a new name and version. Since filename.dist is used as a starting point for the new configuration file, the new configuration file will include the new configuration setting. When a configuration setting is removed, it will disappear from the new configuration file for the same exact reason.

## CONFIGURATION SETTING VERSION
sysconftool looks at both name and version. A configuration setting with the same name but different versions are seen by sysconftool as completely different settings. The existence of version allows a finer-grained control of configuration upgrades, as described below.

sysconftool copies setting values with the same name and version from the old configuration file to the new configuration file. However, the associated descriptive comments are not copied, and are taken from the new filename.dist. Therefore, if a new version of the configuration file contains an updated or an embellished description of a particular setting, it will be included in the new configuration file, but the existing configuration value will be preserved! Generally, if a configuration setting does not change its meaning or function, its name and version should remain the same. Its comments can be edited to fix a typo, or revised in a more substantive fashion. Name and version should only be changed if there's a functional change in the configuration setting.

What to do with name and version after a functional change depends on the nature and the magnitude of the change. The nature and the magnitude of the change must be considered not only with respect to the most recent revision of the application, but to all the previous revisions as well. When in doubt, go based upon the largest change in magnitude, in order to guarantee a functional default setting, from filename.dist, and leave it up to a living being to manually figure it out.

If only the default value of a setting should be changed for new application installation, but the existing installations can continue to use the existing value of the setting, both the name and version should be left alone. Existing configuration settings will be preserved, and new installations will get the new default. The descriptive comment of this setting can be updated too (see above).

This should be done only as long as ALL previous values of this configuration setting will ALWAYS be valid in the new application revision. If some possible values of this configuration setting will no longer be valid, version should be changed. sysconftool does not care how name and version are formatted. Both are opaque labels. The only requirements is for the label to be different. The difference between changing version and changing both name and version is this:

If there's an old configuration setting with the same name but different version, sysconftool will still use the new, safe, default value from filename.dist, however sysconftool will also append an additional comment, on its own accord, reminding the reader that this configuration value has been reset, and the reader should consider whether to manually restore the configuration value from the old configuration.

## MISCELLANEA
When sysconftool decides to keep an existing setting, with the same name and value, it will also insert a short comment to that effect, reminding the reader to check the default in filename.dist.

## SEE ALSO
sysconftool(1)[1].

## AUTHORS
Double Precision, Inc.

## NOTES
1.

sysconftool(1)

[set $man.base.url.for.relative.links]/sysconftool.1.html


secure-logging

package: syslog-ng

title: secure-logging(7)

text:
# secure-logging(7)

## NAME
secure-logging - Forward integrity and confidentiality for system logs

## SYNOPSIS
$(slog --key-file <host key file> --mac-file <MAC file> $RAWMSG)

## DESCRIPTION
Secure logging is an extension to syslog-ng providing forward integrity and confidentiality of system logs. It is implemented in form of a module and is configured as a template in the syslog-ng configuration file.

The main objective of the secure logging module is to provide tamper evident logging, i.e. to adequately protect log records of an information system and to provide a sensor indicating attack attempts. The secure logging module achieves this by authentically encrypting each log record with an individual cryptographic key used only once and protecting the integrity of the whole log archive by a cryptographic authentication code. Each attempt to tamper with either an individual log record or the log archive itself will be immediately detected during log archive verification. Therefore, an attacker can no longer tamper with log records without being detected.

In order to use the log file created by the secure logging module for analysis, the log file must first be decrypted and its integrity verified. This is achieved with a command line utility that is part of the secure logging module and is installed as part of the syslog-ng package. This utility can easily be integrated into the import module of existing analysis environments.

The secure logging environment uses a cryptographic key for encrypting log entries. Each individual log entry is encrypted with its own key which is immediately discarded after successful encryption in order to provide forward integrity. An efficient algorithm generates the key for the next log entry based the key used for encrypting the previous log entry. The resulting chain of keys preserves forward integrity, i.e. a potential attacker cannot deduce the previous key from the current key.

In order to ease log verification and analysis, a sequence number is added to each log entry. This sequence number is also added to the encryption key creating a one-to-one correspondence of the encryption key with the log entry. In order to prevent truncation attacks or deletion of individual log entries, a message authentication code (MAC) is iteratively applied to the complete log archive and stored in a separate file. It is used upon verification to check the integrity of the whole log archive.

Here is an example of three short original log messages that will be sent to a destination with secure logging enabled:

```
This is a log message
And here comes another log message
This is a log message with a longer text that is processed without any problems

```

In order to inspect the status of the secure logging environment, one can check the sequence counter by querying the key file with the slogkey utility like this:

```
user@host:~> slogkey --counter /etc/syslog-ng/host.key
counter=3

```

Counting starts at zero. This is why the counter is set to three after processing three messages.

The output of the secure logging template for the three example messages is shown below. One clearly sees the sequence number that was prepended to each message. The colon indicates the end of the sequence number and the start of the original message. As three message were processed, the sequence counter of the key will be three.

```
AAAAAAAAAAA=:k3/dYpLsgO2tUJKSauo6dycIBzW6OTC3pyA9TP+7AnqFgEojBzgC2rcK4OPfRtr8yg==
AQAAAAAAAAA=:smw0ATISVgN+BYEu5d7OLBE7aQhHpK9Ro4MndmNgSVrqhcmRCBCj6DUnD6ku0Z29CKJ0N6LAJUgByX4Ev+g=
AgAAAAAAAAA=:5UVybnKL1EAbgC4CLfd8HpgurjREf4LEN61/yWHSD2hbXjRD4QmQdtbwguT1chzdItKSQASps9QRIvR5Jd4AHzHfqxI4aRgdUBcNbAq26nwUCg5vPWygjmbtQaxZgCJYkry8slxCigmbTVs=

```

The output of a successful verification run is shown below.

```
0000000000000000: This is a log message
0000000000000001: And here comes another log message
0000000000000002: This is a log message with a longer text that is processed without any problems

```

The original log messages have been successfully restored. Additionally, the sequence counter is also prepended to the clear text messages. This helps when in analyzing problems with a particular log entry. As real log files will contain thousands of entries. the sequence counter eases identification of erroneous entries.

Before the secure logging module can be used as part of an existing syslog-ng installation, several preparatory activities need to be performed.

## KEY GENERATION
In order to bootstrap the system, an initial key k0 must be created and installed on the log host before secure logging environment is started for the first time.

The newly created host key k0 has its counter set to 0 indicating that it represents the initial host key k0. This host key k0 must be kept secret and not be disclosed to third parties. It will be required to successfully decrypt and verify log archives processed by the secure logging environment. As each log entry will be encrypted with its own key, a new host key will be created after successful processing of a log entry and will replace the previous key. Therefore, the initial host key needs to be stored in a safe place before starting the secure logging environment, as it will be deleted from the log host after processing of the first log entry. The following steps must be done before starting the secure logging environment. Steps 1 and 2 are performed with the slogkey utility. See slogkey(1) for details on how to generate a master key and to derive a host key from it. Step 3 and 4 depend on the actual deployment in a target environment.

1.Create a master key

2.Derive an initial host key k0 from a previously created master key

3.Store the initial host key k0 in a safe location outside of the log host

4.Deploy the key k0 on the log host where the secure logging module will be used

## CONFIGURATION
Secure logging is configured by adding the corresponding statements to the syslog-ng.conf file. See syslog-ng.conf(5) for information on how to configure syslog-ng using the configuration file. Details can be found in the The syslog-ng Administrator Guide[1].

Secure logging is implemented as a template and is configured accordingly. Apart from the actual template configuration, no other settings are required in order to activate secure logging. The secure logging is activated by placing the following statement in the configuration file

template("$(slog --key-file <host key file> --mac-file <MAC file> $RAWMSG)\n");

where

slog

The name of the secure logging template function. This name can be also be found by calling syslog-ng with the --module-registry arguments and checking the template-func property of the secure logging module in the corresponding output.

--key-file or -k

The host key. <host key file> is the full path of the file storing the host key on the log host. If this arguments is not supplied or does not point to a valid regular key file, syslog-ng will not start and a display a corresponding error message.

--mac-file or -m

The MAC file. <MAC file> is the full path of the MAC file on the log host. The file does not need to exist, as it will be automatically created upon the initial start. If the path is not correct, syslog-ng will not start and a display a corresponding error message.

$RAWMSG

$RAWMSG provides access to the original log message received at the source. This macro is only available if the store-raw-message flag was set for the source. Otherwise, an empty string will be passed to the secure logging template. If access to the original message is not available, e.g. if the source does not support the store-raw-message flag, then the $MSG macro can also be used. In this case, however, the integrity guarantee provided by secure logging is limited to the content that this macro provides and does not protect the complete original message.

\n

\n is the line separator. This is important, as the secure logging template expects log entries to be separated by a line separator. When detecting a line separator, the log entry is regarded as complete and is encrypted with the current host key. Therefore, only a single line separator is allowed.

The secure logging template can be combined with any source or destination within the following limitations:

•Sources must be line-oriented. Secure logging uses a line separator in order to distinguish between individual log entries. Sources which provide data in a different format, e.g. in the form of raw data obtained directly from a database system, cannot currently be used with the secure logging template, as the separation of log entries is not clearly defined for this type of data.

•Only sources for which the store-raw-message flag is implemented and set do benefit from the integrity guarantee provided by the secure logging template. Secure logging aims at protecting the integrity of complete log messages including all associated meta-data, such as timestamps and host names. syslog-ng parses the log message into its internal format and provide easy access to parts of a message through macros. While this is convenient when rewriting log messages, it is not helpful for secure logging. syslog-ng provides the store-raw-message flag which provides access to a copy of the original log message after parsing. This is the log message processed and protected by the secure logging template. If the source does not support the store-raw-message flag, then the $MSG macro can also be used. However, in this case the integrity guarantee provided by secure logging is limited to the content that this macro provides.

•Log rotation of any kind cannot be used with destinations using secure logging. The reason is that log rotate will overwrite, i.e. delete previous log files. This destroys the cryptographic chain of trust of the log entries making recovery impossible. In order to allow for a an efficient handling of log files, the secure logging environment features iterative verification. Using iterative verification, a log file can be verified in steps. For this to work, the log file must first be downloaded from the log host, together with the corresponding host key and MAC file to a verification host. After this download the log file can be safely deleted from the log host. Verification is then performed on the verification host using the iterative mode of the slogverify utility. See slogverify(1) for details.

The following example configuration shows the use of the secure logging template on a file destination.

```
#############################################################################
# Minimal syslog-ng.conf file with secure logging enabled. Encrypted log
# entries will be logged to a single file called /var/log/messages.slog
#
@version: 4.8
@include "scl.conf"
source s_local {

    system();

    internal();
};
source s_network {

    network(

        transport("udp")

        port(514)

        flags(store-raw-message)

    );
};
# Secure logging template definition
template secure_logging {

    template("$(slog --key-file /etc/syslog-ng/host.key --mac-file /etc/syslog-ng/mac.dat $RAWMSG)\n");
};
# This configures a secure logging destination
destination d_local {
	file("/var/log/messages.slog" template(secure_logging));
};
log {

    source(s_local);

    # This source has the raw message flag set

    source(s_network);

    # This statement activates secure logging for this destination

    destination(d_local);
};

```

## LOG VERIFICATION
In order to analyze the log file created in a secure logging environment, the log files must be decrypted and their integrity be verified. Verification requires both the initial host key k0 and the corresponding MAC file and is performed with the slogverify utility. It is not normally performed on the log host where the secure logging environment is producing log data. In a typical deployment, log files would be retrieved from the log host and transferred to a central log collector where verification it performed. As verification requires the use of the initial host key k0, it should only be performed in a trusted environment.

### Normal mode
In normal mode, a complete log archive is verified at once. In a typical environment, this would mean retrieving a log file together with is MAC file from a log host and retrieving the corresponding initial key k0 form a safe location and supplying them to the slogverify utility. A typical call sequence for verification in normal mode would look like this

slogverify --key-file host0.key --mac-file mac.dat /var/log/messages.slog /var/log/verified/messages

with

host0.key

The initial host key k0. Supplying the initial key k0 is enough for decrypting all log entries, as the key derivation algorithm is able to generate the necessary keys for all subsequent log entries based on the initial key k0.

mac.dat

The MAC file from the log host.

/var/log/messages.slog

The file containing the encrypted log entries as retrieved from a log host.

/var/log/verified/messages

The file receiving the plain text log after decryption.

Log files may become large and not fit into system memory. Verification is therefore performed in chunks. Each part of the log file is transferred to an internal buffer on which verification is performed. After the buffer has been processed, the next chunk is fetched. An optional buffer argument can be supplied to the slogverify utility in order to change the default buffer size of 1000 log entries to a number suitable for the system on which the verification is performed, for example

slogverify --key-file host.key --mac-file mac.dat /var/log/messages.slog /var/log/verified/messages 8000

See slogverify(1) for details on verification in normal mode.

### Iterative mode
Verification in normal mode may not be suitable for some application scenarios. Many log hosts use log rotation in order to preserve storage space. In log rotation, a threshold for the maximum amount of storage space and the number of generations is defined for different type of log files. When either storage space is exhausted or the number of generations is reached, the oldest log file will be overwritten by new incoming log data. This procedure is not possible in secure logging environment, as overwriting, i.e. deleting a log file would break the cryptographic chain that is established between the log entries. This comes as no surprise, as one of the main objectives of secure logging is to protect against deletion of log entries by a potential attacker.

In order allow for a procedure similar to log rotation, the secure logging environment features an iterative mode. In iterative mode, log files can be split into different files and each of these files can be verified separately. Care must be taken when performing verification in iterative mode, as each of the different log files needs to be accompanied by a copy of the host key and the MAC files present on the system at the time of retrieval. A typical usage scenario for the iterative mode would look like this:

1.Define a storage threshold for the secure logging file destination. In this example we assume 500MB.

2.Let the secure logging environment produce log data that is written to the destination until 500MB are reached.

3.Stop the secure logging environment and retrieve the log file, the host key and the MAC files from the log host.

4.Delete the log file on the log host but leave host key and MAC file untouched.

5.Restart the secure logging environment.

6.Perform verification in iterative mode with the log file, the host key and the MAC just retrieved.

Steps 2-6 have to repeated each time the log file reaches a size of 50 MB. Assuming that the log file parts will be named after the iteration, e.g. log.1, log.2, log.3, etc. and a similar convention is applied to the host keys and MAC files, a typical call sequence for the validation of a log file part in iterative mode after three iterations will look like this:

slogverify --iterative --prev-key-file host.key.2 --prev-mac-file mac.dat.2 --mac-file mac.dat /var/log/messages.slog.3 /var/log/verified/messages.3

with

host.key.2

The host key from the previous iteration. In this example, this is the second iteration.

mac.dat.2

The MAC file from the previous iteration. In the example, verification is performed during the third iteration, so the MAC file from the second iteration is required.

mac.dat

The current MAC file from the log host.

/var/log/messages.slog.3

The file part containing the encrypted log entries as retrieved from the log host during the third iteration.

/var/log/verified/messages.3

The file receiving the plain text log after decryption during the third iteration.

In a real deployment, the above steps would typically be automated using a scripting engine.

See slogverify(1) for details on verification in iterative mode.

## FILES
/usr/bin/slogkey

/usr/bin/slogencrypt

/usr/bin/slogverify

/etc/syslog-ng.conf

## SEE ALSO
syslog-ng.conf(5)

slogkey(1)

slogencrypt(1)

slogverify(1)

Note

For the detailed documentation of see The syslog-ng Administrator Guide[1]

If you experience any problems or need help with syslog-ng, visit the syslog-ng mailing list[2].

For news and notifications about of syslog-ng, visit the syslog-ng blogs[3].

For specific information requests related to secure logging send a mail to the Airbus Secure Logging Team <secure-logging@airbus.com>.

## AUTHOR
This manual page was written by the Airbus Secure Logging Team <secure-logging@airbus.com>.

## NOTES
1.

The syslog-ng Administrator Guide

https://www.balabit.com/documents/syslog-ng-ose-latest-guides/en/syslog-ng-ose-guide-admin/html/index.html

2.

syslog-ng mailing list

https://lists.balabit.hu/mailman/listinfo/syslog-ng

3.

syslog-ng blogs

https://syslog-ng.org/blogs/