Syncthing 2.1.7 on AWS User Guide
Overview
This guide covers launching and using the Syncthing 2.1.7 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg file sharing and sync listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.
Syncthing is an open source continuous file synchronisation program. Devices that you pair with each other keep shared folders identical, directly between themselves over an encrypted and mutually authenticated connection, with no central server and no cloud account. An EC2 instance running Syncthing is a device that is always on: your laptops, desktops, servers and phones sync with it whenever they are online, so changes reach your other devices even when those are never online at the same time, and the instance keeps a copy of every shared folder on its own EBS volume.
The cloudimg image locks Syncthing down:
- Nothing shared ships in the image. There is no device identity, certificate, API key or password in the AMI. On your instance's first boot Syncthing generates its own device ID and API key, and the web GUI user
admingets a password unique to your instance. All of them are written to/root/syncthing-credentials.txt(root only). - HTTPS from the first boot. The web GUI listens on
127.0.0.1only. nginx serves it on port 443 with a certificate generated on your instance's first boot; port 80 redirects to HTTPS, and requests for a host name the instance does not serve are dropped. - Sign in through the GUI or use the API key. The GUI uses Syncthing's own sign in page and session cookie, and every REST call needs Syncthing's per session token or the API key, so another website cannot drive your Syncthing through your browser. HTTP Basic authentication is not accepted through nginx (see Step 7).
- Private by default. Usage reporting, crash reporting and automatic upgrades are off, and so are global discovery, relaying, local discovery and NAT traversal: the instance tells no outside service where it is. Your devices connect to it directly at
tcp://<your-host>:22000. You can switch global discovery and relays on deliberately (Step 8). - Confined service. Syncthing runs as the unprivileged
syncthingaccount, can write only its own configuration, index and folders on the data volume, cannot replace its own program, and is blocked (like nginx) from the EC2 instance metadata service. - Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
What is on the image: Syncthing 2.1.7 (MPL-2.0; the project's own signed release build for Linux amd64, verified against the release signature), nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent. The licence, authors and build provenance are in /usr/share/doc/cloudimg/syncthing/.
Default user: ubuntu · Architecture: x86_64 · Recommended instance type: m5.large
Prerequisites
- An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet.
- A security group that allows, from your own networks only:
- TCP 22 (SSH),
- TCP 443 (the web GUI) and TCP 80 (redirects to HTTPS),
- TCP 22000 and UDP 22000 (the Syncthing sync protocol; UDP carries QUIC) from the public addresses of the devices that will sync with this one, or from your VPC range for devices inside AWS.
Step 1: Launch the instance
In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick Syncthing 2.1.7 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large, your key pair, a security group as above, and a subnet. The AMI brings an 8 GiB root volume and a separate 20 GiB data volume that holds Syncthing's state and your synced folders; raise the data volume under Configure storage if you will sync more than that (you can also grow it later, see Step 10).
With the AWS CLI (replace the values in angle brackets; this sets the data volume to 200 GiB):
aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
--instance-type m5.large --key-name <your-key-pair> \
--security-group-ids <your-security-group> --subnet-id <your-subnet> \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--block-device-mappings 'DeviceName=/dev/sdf,Ebs={VolumeSize=200,VolumeType=gp3}' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=syncthing}]'
Your devices reach the instance by its address, so give it a stable one: allocate an Elastic IP and associate it with the instance (a plain public IP changes when the instance is stopped and started).
Step 2: Connect to your instance
| Version | SSH user |
|---|---|
| Syncthing 2.1.7 on Ubuntu 24.04 | ubuntu |
ssh -i <your-key.pem> ubuntu@<public-ip>
Step 3: Check the services
First boot sets the host name and certificate, generates the device identity, API key and password, proves them, and only then opens the site. It takes a few seconds:
systemctl is-active syncthing-set-host syncthing-firstboot syncthing nginx
active
active
active
active
On the network, Syncthing listens only on port 22000 (TCP, and UDP for QUIC) for other devices; its web GUI is on 127.0.0.1:8384 behind nginx (80 and 443). The remaining entries are SSH, Ubuntu's local DNS resolver, the time service and DHCP:
sudo ss -lntup | awk 'NR>1 {print $1, $5}' | sort -u
tcp *:22000
tcp 0.0.0.0:22
tcp 0.0.0.0:443
tcp 0.0.0.0:80
tcp 127.0.0.1:8384
tcp 127.0.0.53%lo:53
tcp 127.0.0.54:53
tcp [::]:22
tcp [::]:443
tcp [::]:80
udp *:22000
udp 127.0.0.1:323
udp 127.0.0.53%lo:53
udp 127.0.0.54:53
udp 172.31.85.189%ens5:68
udp [::1]:323
There is no listener on 21027/udp (local discovery), because a VPC carries no broadcast or multicast traffic.
If nginx is not running, first boot has not finished (or failed, in which case the GUI is never served). Check systemctl status syncthing-firstboot and journalctl -u syncthing-firstboot.
Step 4: Get your password, API key and device ID
sudo cat /root/syncthing-credentials.txt
The file is readable by root only. It holds the GUI address, this instance's sync address, the GUI sign in, the REST API key and the device ID:
# Syncthing on Ubuntu 24.04 (cloudimg AWS Marketplace image) - this instance's web GUI sign-in, REST API key and
# device ID. Generated on this instance at first boot; unique to it and not known to cloudimg or the Syncthing project.
...
SYNCTHING_URL=https://ec2-203-0-113-10.compute-1.amazonaws.com/
SYNCTHING_SYNC_ADDRESS=tcp://ec2-203-0-113-10.compute-1.amazonaws.com:22000
syncthing.admin.user=admin
syncthing.admin.pass=<SYNCTHING_ADMIN_PASSWORD>
syncthing.apikey=<SYNCTHING_API_KEY>
syncthing.device_id=<DEVICE-ID>
Keep the password and the API key secret: either one gives full control of Syncthing, including which folders on the instance are shared with which devices.
You can confirm the sign in from the instance itself. The helper goes through nginx on 443 the way a browser does and checks that an anonymous call and a wrong password are refused, that the password signs in, that the signed in session still needs Syncthing's per session token, and that the API key works:
sudo /usr/local/sbin/syncthing-verify.sh
SYNCTHING_ROUNDTRIP_OK (https://ec2-203-0-113-10.compute-1.amazonaws.com/ via 127.0.0.1: 403 anonymous, 403 wrong password, 204 sign-in, CSRF enforced, API key v2.1.7)
Step 5: Sign in to the web GUI
Open the SYNCTHING_URL address in your browser. The certificate is self signed until you install your own (Step 9), so the browser warns you once; before you continue, compare the fingerprint it shows with the one on the instance:
sudo openssl x509 -in /etc/ssl/syncthing/syncthing.crt -noout -fingerprint -sha256
Sign in as admin with the password from Step 4:

The GUI opens on the dashboard: Folders on the left (a new instance has none), This Device on the right with its listeners (2/2: TCP and QUIC on 22000), its short device ID and version, and Remote Devices below. In this example a second device has already dialled the instance and asks to be added:

Change the GUI password to one of your own under Actions → Settings → GUI (and Save). The credentials file is not updated when you do, so store the new password safely. Keep that tab closed when someone is looking over your shoulder: it shows the API key, which you can also regenerate there.
Step 6: Pair your devices and share a folder
Syncthing devices only talk to devices they have been told about, identified by their device ID. Show this instance's ID:
sudo grep '^syncthing.device_id=' /root/syncthing-credentials.txt
(In the GUI: Actions → Show ID, which also shows it as a QR code for the Syncthing apps on phones.)
Because global discovery is off, tell your other devices where the instance is:
- On your laptop, desktop or server, install Syncthing from syncthing.net, open its GUI and choose Add Remote Device. Paste the instance's device ID, and on the Advanced tab set Addresses to the
SYNCTHING_SYNC_ADDRESSfrom the credentials file (for exampletcp://ec2-203-0-113-10.compute-1.amazonaws.com:22000, or your own name and Elastic IP). Save. - Your device connects to the instance on port 22000 and the instance shows New Device ... wants to connect. Choose Add Device, give it a name and Save:

- Share a folder from your device with the instance (in the folder's Sharing tab tick the instance). The instance shows New Folder ... wants to share folder; choose Add. The folder path defaults to
/var/lib/syncthing/folders/<label>on the data volume; Save:

You can equally start on the instance: Add Folder there, tick your device on its Sharing tab, and accept the folder on your device.
The instance then pulls the folder's files and keeps them in sync. When the folder and the device both show Up to Date, the instance holds a full copy:

The instance never needs to reach your devices: as long as they can reach it on 22000, they connect to it, so devices behind a home router or a laptop on the move work without any port forwarding on their side. Two devices that cannot reach each other directly still stay in sync through the instance when both share the folder with it.
Step 7: Use the REST API
Scripts use Syncthing's REST API at https://<your-host>/rest/... with the API key in an X-API-Key header (the stnoupgrade tag shows that upgrades are disabled). On the instance, this reads the key from the credentials file into curl's configuration on standard input, so the key never appears on a command line or in your shell history:
sudo sed -n 's/^syncthing\.apikey=\(.*\)$/header = "X-API-Key: \1"/p' /root/syncthing-credentials.txt \
| curl -s --cacert /etc/ssl/syncthing/syncthing.crt -K - https://127.0.0.1/rest/system/version \
| jq '{version, codename, date, isRelease, tags}'
{
"version": "v2.1.7",
"codename": "Hafnium Hornet",
"date": "2026-10-20T19:54:38Z",
"isRelease": true,
"tags": [
"stnoupgrade"
]
}
With a device connected, /rest/system/connections lists it; here the second device from Step 6 dialled the instance on 22000:
{
"EASV76M-PVPKKQY-OZMTYK4-PWH3E7A-TRPD32I-O72IS6C-6BLVKXE-BFUW3AQ": {
"connected": true,
"address": "172.31.83.184:22000",
"type": "tcp-server",
"clientVersion": "v2.1.7"
}
}
HTTP Basic authentication is not accepted through nginx. Syncthing itself would accept the GUI user name and password as Basic auth on every REST route, which would let a password guessing tool bypass the sign in page's limits, so nginx removes the Authorization header before it reaches Syncthing. A Basic auth request is therefore treated like an anonymous one and refused:
curl -s -o /dev/null -w '%{http_code}\n' --cacert /etc/ssl/syncthing/syncthing.crt -u admin:not-the-password https://127.0.0.1/rest/system/version
403
Use the GUI's sign in for people and the API key for scripts and tools.
Step 8: Discovery, relays and the sync port
The instance starts with every outside service off, which you can confirm through the API:
sudo sed -n 's/^syncthing\.apikey=\(.*\)$/header = "X-API-Key: \1"/p' /root/syncthing-credentials.txt \
| curl -s --cacert /etc/ssl/syncthing/syncthing.crt -K - https://127.0.0.1/rest/config/options \
| jq '{listenAddresses, globalAnnounceEnabled, localAnnounceEnabled, relaysEnabled, natEnabled, urAccepted, autoUpgradeIntervalH, crashReportingEnabled}'
{
"listenAddresses": [
"tcp://0.0.0.0:22000",
"quic://0.0.0.0:22000"
],
"globalAnnounceEnabled": false,
"localAnnounceEnabled": false,
"relaysEnabled": false,
"natEnabled": false,
"urAccepted": -1,
"autoUpgradeIntervalH": 0,
"crashReportingEnabled": false
}
The same settings are on the Connections tab of Actions → Settings:

- Sync port. Other devices connect to the instance on TCP 22000 and UDP 22000 (QUIC). Allow both in the security group from the networks your devices use; nothing else needs to reach Syncthing. If you change the listen address, change the security group to match.
- Global discovery lets your devices find the instance by device ID alone, without an address. Syncthing then announces this instance's device ID and addresses to the global discovery servers run by the Syncthing project, and asks them for your other devices' addresses. Switch it on only if you want that, by ticking Global Discovery on the Connections tab and Save, or through the API:
sudo sed -n 's/^syncthing\.apikey=\(.*\)$/header = "X-API-Key: \1"/p' /root/syncthing-credentials.txt \
| curl -s --cacert /etc/ssl/syncthing/syncthing.crt -K - -X PATCH -H 'Content-Type: application/json' \
-d '{"globalAnnounceEnabled": true}' https://127.0.0.1/rest/config/options
- Relaying lets two devices that cannot connect directly exchange data through the public Syncthing relays (the data stays end to end encrypted, but it passes through a third party's server, and relays are slower). The instance has a public sync port, so devices that can reach it never need a relay. To allow relays, tick Enable Relaying or send
{"relaysEnabled": true}in the same way; your devices learn each other's relay addresses through global discovery, so enable both. - Usage reporting, crash reporting and automatic upgrades stay off. The Syncthing program on the image cannot replace itself; cloudimg publishes a new version of the image for each new Syncthing release (see Step 10).
Step 9: Use your own host name and certificate
Point a DNS record at the instance's Elastic IP, then tell the instance its name. This mints a new self signed certificate for that name, updates the nginx host rule and the GUI and sync addresses in the credentials file, and keeps the name across reboots:
sudo syncthing-set-hostname sync.example.com
It prints the new certificate's SHA-256 fingerprint, which your browser will show when you next connect. Update the address of the instance on your other devices (Edit Device → Advanced → Addresses) to tcp://sync.example.com:22000.
To use a certificate from a public authority for the GUI instead, replace /etc/ssl/syncthing/syncthing.crt (full chain) and /etc/ssl/syncthing/syncthing.key (mode 0600, owned by root) with your own and run sudo systemctl reload nginx. Running syncthing-set-hostname again later would replace them with a new self signed pair. The sync protocol on 22000 does not use this certificate: devices authenticate each other by device ID, whatever the name.
Step 10: Storage, persistence and updates
Syncthing's configuration, its index database and your synced folders live on the data volume at /var/lib/syncthing, mounted by file system UUID with noexec, nosuid and nodev:
findmnt -no SOURCE,FSTYPE,OPTIONS /var/lib/syncthing
/dev/nvme1n1 ext4 rw,nosuid,nodev,noexec,relatime
sudo ls -la /var/lib/syncthing
total 36
drwxr-xr-x 6 root root 4096 Oct 30 22:07 .
drwxr-xr-x 49 root root 4096 Oct 30 22:05 ..
drwx------ 2 syncthing syncthing 4096 Oct 30 22:23 config
drwx------ 3 syncthing syncthing 4096 Oct 30 22:17 folders
drwx------ 3 syncthing syncthing 4096 Oct 30 22:06 index
drwx------ 2 root root 16384 Oct 30 22:04 lost+found
Shared folders are created under folders/ and owned by the syncthing account, which is the only account Syncthing can write as. To place files into a synced folder from the instance's shell, write them as that account, for example:
sudo -u syncthing cp /home/ubuntu/report.pdf /var/lib/syncthing/folders/Documents/
Every service is enabled, so Syncthing returns after a reboot or a stop and start, with the same device ID, folders and password. Unattended security upgrades keep the operating system and nginx patched:
systemctl is-enabled syncthing nginx unattended-upgrades
enabled
enabled
enabled
To grow the data volume, enlarge the EBS volume in the EC2 console and then extend the file system online:
sudo resize2fs $(findmnt -no SOURCE /var/lib/syncthing)
Syncthing is a sync tool, not a backup: a file deleted or overwritten on one device is deleted or overwritten on the others. Turn on File Versioning for a folder (in its Edit dialog) to keep old versions on the instance, and take EBS snapshots of the data volume (or use AWS Backup) for real backups. To move to a newer Syncthing release, launch the new version of the image, pair it with your devices and share the folders with it; Syncthing fills it from your other devices.
Security notes
- No shared secret ships in the image. The device certificate and key, the GUI's own certificate, the API key, the GUI password (stored by Syncthing as a bcrypt hash), the nginx certificate and the credentials file are all generated on your instance's first boot. nginx does not serve the GUI until first boot has generated them and proved that the password and the API key work.
- Fail closed. If first boot cannot complete, the GUI is never served and Syncthing does not start with a default configuration.
- Confined service. Syncthing runs as the
syncthingaccount with no login shell, no capabilities and no core dumps, with the operating system read only to it except itsconfig,indexandfoldersdirectories, and with--no-upgrade(its upgrade check answers 501 and the program is owned by root). Syncthing, nginx and the first boot step that generates the identity and password cannot reach the EC2 instance metadata service (IPAddressDeny); only the step that looks up the instance's public name uses it, with IMDSv2. - Web GUI behind nginx. Syncthing's own check that the GUI is addressed as
localhoststays on, nginx passes the real client address (taken from the connection, never from a request header) so failed sign ins are logged against the right address, and sign ins are rate limited. Syncthing's debugging and upgrade routes additionally refuse requests that do not come from the GUI's own page. - Web GUI libraries. The Syncthing 2.1.7 web GUI bundles AngularJS 1.3.20 and moment 2.19.4 (and Bootstrap 3.4.1). Both have published advisories rated HIGH for which no fixed release exists on those lines: AngularJS CVE-2026-11998, CVE-2024-21490 and CVE-2019-10768, and moment CVE-2022-31129 and CVE-2022-24785. cloudimg reviewed each against this GUI and none is reachable: the GUI defines no resource URL policy with regular expressions and loads only fixed templates, uses no
ng-srcset, never callsangular.merge, gives moment only timestamps produced by Syncthing itself, and the moment locale issue affects Node.js only. The libraries run in your browser after you have signed in. They are shipped unchanged from the Syncthing release; cloudimg will publish a new version of the image when Syncthing updates them. - Syncthing itself (the Go program) has no known vulnerability reachable in this release: it is built by the Syncthing project with Go 1.27.3, and every published Syncthing advisory was fixed in earlier releases.
- Restrict access. Allow 22/tcp only from your management network, 80/443 only from the networks that use the GUI, and 22000 TCP/UDP only from the networks of your devices. A device ID alone does not let anyone sync with the instance: you have to accept each device and each folder.
Architecture summary
| Component | Detail |
|---|---|
| Sync engine | Syncthing 2.1.7 (MPL-2.0), /usr/local/bin/syncthing, account syncthing, syncthing.service |
| Sync protocol | 22000/tcp (TLS) and 22000/udp (QUIC), device to device authentication by device ID |
| Web GUI and REST API | Syncthing on 127.0.0.1:8384, served by nginx on 443 (HTTPS, per instance certificate in /etc/ssl/syncthing); 80 redirects to HTTPS |
| Sign in | GUI user admin (session cookie), REST API key in the X-API-Key header; Basic auth not accepted through nginx |
| Discovery | Global and local discovery, relays, NAT traversal off; devices connect to tcp://<host>:22000 |
| Your files | /var/lib/syncthing/folders on the 20 GiB data volume (resizable, mounted noexec) |
| State | /var/lib/syncthing/config (configuration, device key), /var/lib/syncthing/index (index database) |
| Credentials | /root/syncthing-credentials.txt, mode 0600, root only |
| First boot | syncthing-set-host.service (host name and certificate), syncthing-firstboot.service (device identity, API key, password) |
| Tools | syncthing-set-hostname, syncthing-verify.sh |
| Ports | 22 SSH, 80 redirect, 443 web GUI, 22000 TCP/UDP sync |
| Base image | Ubuntu 24.04 LTS, fully patched, unattended security upgrades enabled, IMDSv2 required |
Support
cloudimg images come with 24/7 support. Email support@cloudimg.co.uk with your AWS account ID and the instance ID. For Syncthing itself, see the Syncthing documentation and the Syncthing forum.
Syncthing is a trademark of the Syncthing Foundation. cloudimg is not affiliated with, endorsed by or sponsored by the Syncthing Foundation or the Syncthing project.