Support UNIX URLs
Relevant components
- [x] Standalone tray application (based on Qt Widgets)
- [x] Plasmoid/applet for Plasma desktop
- [ ] Dolphin integration
- [ ] Command line tool (
syncthingctl) - [ ] Integrated Syncthing instance (
libsyncthing) - [ ] Android app or mobile UI in general
- [ ] Backend libraries
Environment and versions
- Syncthingtray: 1.7.6-1.38f614f
- Qt version: 6.8.3
- Operating system (name and version): Archlinux
Bug description
Syncthingtray not accepting unix:/// URLs for Syncthing URL field
Steps to reproduce
- Under Settings / Startup / Arguments add
--gui-address=unix:///run/syncthing/uid1000.unix - Under Tray / Syncthing URL, set the value
unix:///run/syncthing/uid1000.unix. - Click Apply. Error messages appear that the URL is not valid (It is, but it's faily niche)
Expected behavior Tray should delegate validating the URL to the syncthing instance it connects to. If it fails it should fail with a generic error stating this.
Screenshots
Additional context This is absolutely a low-priority issue. I unfortunately don't have time to contribute anything towards this at the moment, which is why I'm writing this.
This is not supported. You probably wanted to open a feature request and not a bug.
An issue requesting this feature has already been created but I can't find it anymore. There we established that this is actually supposed to work as of a certain Qt version but it didn't work nevertheless. So this should probably be revisited but I haven't had the time yet. (I'm currently spending most time on the Android port and bug fixes.)
I at least found the relevant Qt upstream feature request again: https://bugreports.qt.io/browse/QTBUG-102855
So this is supposed to work as of Qt 6.8.0.
Judging by https://codereview.qt-project.org/c/qt/qtbase/+/550202/9 you need to use unix+http (so unix+http:///run/syncthing/uid1000.unix in your case). You can try testing that again but according to the user that reported the previous issue this didn't work.
EDIT: The initially reported issue was actually a discussion, see https://github.com/Martchus/syncthingtray/discussions/249.
Hey thanks for the quick reply! Sorry about the bug/feature request and thanks for fixing it.
While unix+http stops the error, it still doesn't seem to be working. Syncthing itself start, but tray cannot connect to it.
Maybe you want to regenerate your API key now :-)
Syncthing itself doesn't seem to be starting - See screenshot
Where do you see that Syncthing itself isn't starting in that screenshot? I don't see the Syncthing logs there (except for a few lines in the background).
Maybe you'll have to disable HTTPs in Syncthing as perhaps really only unix+http but not unix+https is supported. (And when optimizing this for local access only I suppose using TLS would not be wanted anyway.)
Hey sorry I didn't reply. I posted the screenshot. I also made an edit, but I think you quoted an earlier version.
Anyway syncthing is running (I explicitly restarted it, and the socket exists, so it's working). TLS is disabled.
What does regenerting the API key do and how do I do this via UNIX sockets?
Environment and Versions
- syncthingtray-qt6 on AUR (Plasmoid 1.7.8)
- Qt version: Qt 6.9.1
- Operating system:
Linux cipher-archlinux 6.12.33-1-lts #1 SMP PREEMPT_DYNAMIC Tue, 10 Jun 2025 13:16:59 +0000 x86_64 GNU/Linux
Notes
I've verified that Syncthing responds to authenticated API requests on a UDS using:
$ curl --unix-socket /run/user/1000/syncthing/syncthing.socket http://who-cares/rest/noauth/health
{
"status": "OK"
}
$ curl -H 'Authorization: Bearer <TOKEN>' --unix-socket /run/user/1000/syncthing/syncthing.socket http://who-cares/rest/system/version
{
"arch": "amd64",
"codename": "Gold Grasshopper",
"container": false,
"date": "2025-06-02T14:20:01-07:00",
"extra": "",
"isBeta": false,
"isCandidate": false,
"isRelease": true,
"longVersion": "syncthing v1.29.7 \"Gold Grasshopper\" (go1.24.3 linux-amd64) syncthing@archlinux 2025-06-02 21:20:01 UTC [noupgrade]",
"os": "linux",
"stamp": "1748899201",
"tags": [
"noupgrade"
],
"user": "syncthing",
"version": "v1.29.7"
}
I configured the Plasmoid as follows:
And the way Syncthing is configured is split across the systemd configuration and the config.xml configuration:
XML snippet:
<gui enabled="true" tls="false" debugging="false" sendBasicAuthPrompt="false">
<address>127.0.0.1:8384</address>
<metricsWithoutAuth>false</metricsWithoutAuth>
<apikey>TOKEN</apikey>
<theme>default</theme>
</gui>
# /usr/lib/systemd/user/syncthing.service
[Unit]
Description=Syncthing - Open Source Continuous File Synchronization
Documentation=man:syncthing(1)
StartLimitIntervalSec=60
StartLimitBurst=4
[Service]
ExecStart=/usr/bin/syncthing serve --no-browser --no-restart --logflags=0
Restart=on-failure
RestartSec=1
SuccessExitStatus=3 4
RestartForceExitStatus=3 4
# Hardening
SystemCallArchitectures=native
MemoryDenyWriteExecute=true
NoNewPrivileges=true
# Elevated permissions to sync ownership (disabled by default),
# see https://docs.syncthing.net/advanced/folder-sync-ownership
#AmbientCapabilities=CAP_CHOWN CAP_FOWNER
[Install]
WantedBy=default.target
# /home/cipher/.config/systemd/user/syncthing.service.d/override.conf
[Service]
# github.com/syncthing/syncthing/issues/9855
ExecStart=
ExecStart=/usr/bin/syncthing serve --no-browser --no-restart --logflags=0 \
--gui-address=unix://%t/syncthing/syncthing.socket --skip-port-probing
RuntimeDirectory=syncthing
The logs for syncthingtray basically stop after the request URL is updated:
$ journalctl -b -t plasmashell -t syncthingtray-qt6 | tail -n 15
Jun 19 13:40:33 cipher-archlinux plasmashell[76016]: Error: Unable to request folder statistics: Connection refused
Jun 19 13:40:33 cipher-archlinux plasmashell[76016]: request URL: http://127.0.0.1:8384/rest/db/status?folder=rjf6d-tkase
Jun 19 13:40:33 cipher-archlinux plasmashell[76016]: Error: Unable to request folder statistics: Connection refused
Jun 19 13:40:33 cipher-archlinux plasmashell[76016]: request URL: http://127.0.0.1:8384/rest/db/status?folder=sm3cd-meats
Jun 19 13:40:33 cipher-archlinux plasmashell[76016]: Error: Unable to request Syncthing config: Connection refused
Jun 19 13:40:33 cipher-archlinux plasmashell[76016]: request URL: http://127.0.0.1:8384/rest/system/config
Jun 19 13:40:33 cipher-archlinux plasmashell[76016]: Error: Unable to request Syncthing config: Connection refused
Jun 19 13:40:33 cipher-archlinux plasmashell[76016]: request URL: http://127.0.0.1:8384/rest/system/config
Jun 19 13:40:33 cipher-archlinux plasmashell[76016]: Error: Unable to request Syncthing config: Host not found
Jun 19 13:40:33 cipher-archlinux plasmashell[76016]: request URL: unix+http:///run/user/1000/syncthing/syncthing.service/rest/system/config
Jun 19 13:49:15 cipher-archlinux plasmashell[76016]: qt.qml.signalhandler: Property 'onPressed' of object CompactRepresentation_QMLTYPE_1039(0x568258dc0840) is a signal handler. You should not call it directly. Make it a proper function and call that or emit the signal.
Jun 19 13:55:15 cipher-archlinux plasmashell[76016]: file:///usr/share/plasma/plasmoids/org.kde.plasma.notifications/contents/ui/delegates/DelegatePopup.qml:147:17: QML Body: Binding loop detected for property "width"
Jun 19 13:55:15 cipher-archlinux plasmashell[76016]: file:///usr/share/plasma/plasmoids/org.kde.plasma.notifications/contents/ui/delegates/DelegatePopup.qml:147:17: QML Body: Binding loop detected for property "width"
Jun 19 14:06:17 cipher-archlinux plasmashell[76016]: file:///usr/share/plasma/plasmoids/org.kde.plasma.taskmanager/contents/ui/main.qml:331:9: QML QQuickItem (parent or ancestor of QQuickDragAttached): Don't know how to encode variant of type QMetaType() as mime type ""
Jun 19 14:06:17 cipher-archlinux plasmashell[76016]: file:///usr/share/plasma/plasmoids/org.kde.plasma.taskmanager/contents/ui/main.qml:331:9: QML QQuickItem (parent or ancestor of QQuickDragAttached): Don't know how to encode variant of type QMetaType() as mime type "application/x-orgkdeplasmataskmanager_taskbuttonitem"
So I take that as a "it work if configured correctly". If that's correct then I would close this issue and perhaps extend the README with your findings.
So I take that as a "it work if configured correctly". If that's correct then I would close this issue and perhaps extend the README with your findings.
No, it doesn't work. Actually, I think this requires some code change. I'll post a sample snippet later of what that's necessary.
I didn't want to traipse through the Qt source code to understand how the unix+http scheme is meant to work, but I did at least figure it out by looking at the test cases.
Take a look at this file: https://github.com/qt/qtbase/blob/fb93950e7ebf7d4bb336e7c9f7a60a6bafdb60ed/tests/auto/network/access/qnetworkreply_local/tst_qnetworkreply_local.cpp
This is a repository that shows how to send a request to a UDS. The question is what the design should look like inside of syncthingtray. I think that this requires another input field for the socket file path, which is only used if the scheme starts with one of local or unix.
Ah, so one cannot just spend the path for the specific route. So the key seems to be specifying the URL as usual and passing the special unix+http URL only in addition via QNetworkRequest::FullLocalServerNameAttribute.
I guess this might indeed require another input field. Except the who-cares part really doesn't matter (including a potential port) because then we could just make that up internally. I doubt someone uses a Unix socket and a path prefix at the same time.
Maybe another field is the best option as it is most straightforward and can already show how a Unix socket URL would look like via its placeholder text. It could be hidden under advanced options.
I'm a bit sick but maybe this is simple enough to come up with an implementation quickly. I just need to introduce a new setting and use it when making the QNetworkReply.
I pushed a commit which makes this work and documented it in the README. I tested it locally by adding the CLI parameters mentioned in @ssmendon's systemd unit file. Note that the web view doesn't work with this. I am not sure whether Chromium (and Qt WebEngine) support this.
Will try shortly. Get better soon @Martchus!
By the way, how is access to the official web UI (via some web browser) done in a setup like this? Using a UNIX domain socket is really easy to configure and perhaps more efficient but if one cannot access the official web UI it doesn't seem to be very useful after all.
It would be possible to rewrite the URL passed to Qt WebEngine or a Chromium-based browser or even just to the standard web browser in some way to make the "Open Syncthing" button work. I just don't know how the URL needs to look like for Chromium or other browsers and a brief search didn't yield much results. The best result I got is this issue marked as "Won't fix" which would mean it is simply not possible in Chromium right now. (Btw, the AI results on the topic really showed how useless AI can be; it came up with something that would be nice to have but didn't actually work so the AI (Gemini in this case) was probably just hallucinating.)
FWIW, I've been using Syncthing happily for a few months, configured via NixOS, without either the tray applet or the web UI. Just having the tray applet would be a big step forward. :)
By the way, how is access to the official web UI (via some web browser) done in a setup like this?
It doesn't really work, basically. I think there are a lot of concerns about how to specify the path (there's no standard for this), especially since URLs can be a massive security issue.
Like, imagine if a website could perform a CSRF and access some known socket on the filesystem or something. See also: https://github.com/whatwg/url/issues/577
Pure speculation: but this is probably why Qt has an entirely separate attribute to specify the socket path.
In terms of practical solutions, I've seen a SOCKS5 proxy that handles such requests (because Firefox allows SOCKS5 over UDS). See: https://github.com/randomstuff/soxidizer?tab=readme-ov-file
My thought was just to get this to work in QtWebEngine by implementing a custom URL scheme or something. Then internally that scheme would push packets to the socket directly.
Looks like there's actually an API that would allow creating a custom scheme: https://doc.qt.io/qt-6/qwebengineurlschemehandler.html
By the way, how is access to the official web UI (via some web browser) done in a setup like this? Using a UNIX domain socket is really easy to configure and perhaps more efficient but if one cannot access the official web UI it doesn't seem to be very useful after all.
It would be possible to rewrite the URL passed to Qt WebEngine or a Chromium-based browser or even just to the standard web browser in some way to make the "Open Syncthing" button work. I just don't know how the URL needs to look like for Chromium or other browsers and a brief search didn't yield much results. The best result I got is this issue marked as "Won't fix" which would mean it is simply not possible in Chromium right now. (Btw, the AI results on the topic really showed how useless AI can be; it came up with something that would be nice to have but didn't actually work so the AI (Gemini in this case) was probably just hallucinating.)
It would be possible to access the web interface by binding the socket to a loopback device so you can access it via TCP.
Actually (not sure where I saw this) I read that chromium actually does implement the functionality to access HTTP via UNIX sockets, but it's blocked/disabled. If that were patched or the configured, it could work too
By the way, how is access to the official web UI (via some web browser) done in a setup like this?
It doesn't really work, basically. I think there are a lot of concerns about how to specify the path (there's no standard for this), especially since URLs can be a massive security issue.
Like, imagine if a website could perform a CSRF and access some known socket on the filesystem or something. See also: whatwg/url#577
Pure speculation: but this is probably why Qt has an entirely separate attribute to specify the socket path.
In terms of practical solutions, I've seen a SOCKS5 proxy that handles such requests (because Firefox allows SOCKS5 over UDS). See: https://github.com/randomstuff/soxidizer?tab=readme-ov-file
My thought was just to get this to work in QtWebEngine by implementing a custom URL scheme or something. Then internally that scheme would push packets to the socket directly.
CSRF prevention is not the responsibility of the URL but of the program implementing it. BTW, if UNIX sockets became first-class authorities, then the same CORS rules apply to UNIX sockets as to other IP authorities, so I see this as a non-issue.
I was curious whether this could be implemented via https://doc.qt.io/qt-6/qwebengineurlschemehandler.html so I gave it a try. Unfortunately it doesn't really work. The problem is that it apparently cannot load CSS and JavaScript files. This is weird because it actually seems to request those via the scheme handler, too. Maybe my implementation is still missing something.
Even though it doesn't really work I pushed the implementation on master as https://github.com/Martchus/syncthingtray/commit/6bf42d2007eff1ff993b8291febe7fdd6b5c9f65 because it won't disturb anything else and this way I can avoid a separate branch that will need regular rebasing. So you can have a look if you're interested. One has to comment-in //#define SYNCTHINGWIDGETS_HAS_SCHEME_HANDLER for this to be enabled at all. (I'll either make this a proper build system switch or just enable it always. Since I haven't decided that yet this line is just commented-out for now.)
Wow this is sick! I don't know enough about it to be helpful here but that's definitely promising! Thanks for your efforts
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I haven't been working on this but I could give it another try at some point.
I'm also contemplating on using UNIX domain sockets as an optional optimization within the Android app where this would reduce overhead and at the same time ensure no other apps can access the API/frontend¹.
¹ So far the app uses HTTPs and prompts the user to set a password for the GUI to be secure. However, if one doesn't need to access the web GUI this effort could be avoided completely.
With https://github.com/Martchus/syncthingtray/commit/ae9800b5deea1924ecbd84078bb3611953141818 it is now possible to use a UNIX domain socket in the mobile UI where it makes especially sense (see my previous comment). I tested that under GNU/Linux and Android (in the emulator) and it works.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
There's nothing new as I haven't tried making the web view work.
Unfortunately I've noticed that using the Unix domain socket in the mobile app leads to the app getting stuck re-connecting in case Syncthing is restarted, e.g. when exporting settings. I'm not sure whether that's new since some update of Qt; it definitely happens since I've updated to Qt 6.10.0. It does not happen when using a normal TCP connection.
Restarting just the UI process of the app helps. That means Syncthing is definitely listening correctly on the Unix socket in this situation. I also made it now display the URL in the launcher settings and the UI uses the correct URL. So I suspect the problem is somewhere within the Qt networking library.
I was also able to reproduce this sometimes also under GNU/LInux using the mobile UI (and not just under Android).
(I'm mainly writing this for myself so I don't forget what I have already tested/established regarding this problem. If anyone has further information that'll be appreciated, too of course.)
I of course would offer any help I can, but I simply don't know enough about Qt or Android or whatnot to be particularly useful. It's cool to see though that you're taking this issue seriously.