Compare commits

...
Author SHA1 Message Date
alexbelgiumandClaude Opus 5.5 6cb6a624c0 joplin_desktop: drop --disable-dev-shm-usage, Joplin rejects unknown flags
Joplin validates its argv against an allow-list (processStartFlags.ts) and
aborted with 'Unknown flag: --disable-dev-shm-usage', so the app never opened.
Record the trap in the workflow skill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:40:39 +02:00
alexbelgiumandClaude Opus 5.5 1e9936a3ce fix(90-ssl): honour own certificates when data_location is relocated
20-folders.sh rewrites the data path in /defaults/default.conf before 90-ssl.sh
runs, so the literal /config/data/ssl/... match missed and own certificates were
silently ignored. Replace whatever path the ssl_certificate directives hold.
Shared with webtop/webtop_kde; their versions are intentionally not bumped, so
they pick this up on their next release. Also restores panel_admin: false.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:14:09 +02:00
alexbelgiumandClaude Opus 5.5 b8aec28b48 joplin_desktop: drop panel_admin (admin-only is the default; linter rejects it)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:11:37 +02:00
alexbelgiumandClaude Opus 5.5 e64f5f8ed9 joplin_desktop: admin-only panel; steer direct access to https/ingress in README
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:09:44 +02:00
alexbelgiumandClaude Opus 5.5 ce8c1586ec feat(joplin_desktop): new add-on streaming Joplin desktop via Selkies (#3100)
Wraps lscr.io/linuxserver/joplin (amd64 only; Joplin ships no Linux arm64
build) and shares the Selkies startup scripts with webtop/claude_desktop by
symlink, the same way webtop_kde does. Chromium is told to keep shared memory
out of /dev/shm because Home Assistant ignores shm_size.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:38:23 +02:00
AlexandreandClaude Opus 5.5 5949321a55 fix(filebrowser_quantum): remove doubled status-bar inset in the HA app (#3111)
* fix(filebrowser_quantum): drop the doubled status-bar inset in the HA app

2.0 sets viewport-fit=cover and pads its header by env(safe-area-inset-top);
inside the ingress panel HA's toolbar already handles that inset. Rewrite it
to viewport-fit=auto on the ingress listener only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(filebrowser_quantum): zero only the top safe-area inset on ingress

Replace the viewport-fit rewrite with --safe-area-top: 0px set on <html>
from the existing nonce script. It touches only the top inset (bottom and
side insets keep upstream behaviour) and works whether or not the browser
passes the parent's insets into the ingress iframe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 08:31:54 +02:00
AlexandreandClaude Opus 5.5 4199b7e292 fix(filebrowser_quantum): write the v2 config format so 2.0.0 starts (#3110)
* fix(filebrowser_quantum): write the v2 config format so 2.0.0 starts

v2 rejects the string server.database, the 1.x server.port/listen/baseURL
keys and the FILEBROWSER_DATABASE variable, so both fresh installs and
upgrades died at startup. Write http.* and server.database.path, and point
migrateFrom at an existing 1.x BoltDB so upstream migrates it on first start.

Fixes #3109

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(filebrowser_quantum): reset 1.x configs to the v2 default on upgrade

Old installs carry a config copied from a 1.x image default, whose
userDefaults layout v2 rejects as unknown fields. Deleting keys one by one
cannot cover every 1.x variant, so back the file up and start from the v2
default, which the script then fills in as on a fresh install.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(filebrowser_quantum): clarify migrateFrom comment

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(filebrowser_quantum): follow the v2 migration guide and upstream healthcheck

Set migrateFrom only until the SQLite database exists, set
http.trustProxyHeaders for the nginx subpath, and check upstream's
${baseURL}health endpoint instead of an nginx-only stub.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(filebrowser_quantum): convert 1.x configs in place instead of resetting

Resetting to the v2 default dropped extra sources (breaking shares on them)
and auth/OIDC settings. Both 1.x and 2.0 reject unknown keys, so the keys a
1.5.x config can hold that 2.0 lacks are exactly the settings-struct diff:
move the server http keys under http and drop the removed ones.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(filebrowser_quantum): fix CHANGELOG entry

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(filebrowser_quantum): ask users to back up before the 2.0 upgrade

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(filebrowser_quantum): keep server.database siblings, sanitize direct XFF

Set only server.database.path (dropping migrateFrom) so user-set keys such
as activity survive, and replace X-Forwarded-For on the published 8071
listener now that FileBrowser trusts proxy headers for login rate limits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(filebrowser_quantum): drop panel_admin default flagged by the add-on linter

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Revert "fix(filebrowser_quantum): drop panel_admin default flagged by the add-on linter"

Keep panel_admin: true explicit, per maintainer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(filebrowser_quantum): simplify the healthcheck

Curl the app root: v2 answers 200, or 301 to the baseURL, which curl -f
accepts, so the baseURL no longer has to be read from the config.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 08:01:34 +02:00
30 changed files with 515 additions and 23 deletions

No files matched your search

@@ -220,6 +220,14 @@ Assistant **ignores** the add-on's `shm_size`, so the real size varies per insta
on one host. Detect at runtime rather than assuming either way; keep the flag when the size
cannot be determined, because the crash it prevents is worse than its overhead.
**Not every Electron app accepts arbitrary Chromium switches.** Joplin parses its own argv
against an allow-list and aborts on anything else: `--disable-dev-shm-usage` produced
`An error occurred: Unknown flag: --disable-dev-shm-usage` and no app window
(`packages/lib/utils/processStartFlags.ts`; it accepts `--no-sandbox`, `--ozone-platform=`,
`--disable-gpu` and a few others). The build-time `grep` that "verified" the flag only proved
the text was in the wrapper, not that the app tolerated it. Check the app's argument parser before
passing a Chromium flag to anything that is not Chromium itself (joplin_desktop, PR #3112).
## CI and review bots
**What CI actually gates** — checked against the workflows, because assuming costs a cycle.
+17
View File
@@ -1,4 +1,21 @@
## 2.0.0.2 (2026-10-11)
- Remove the empty band above the search bar in the Home Assistant app (portrait): 2.0 padded its header for the phone status bar, which HA already does. The top inset is set to 0 on ingress only.
## 2.0.0.1 (2026-10-11)
- ⚠️ **Back up before updating.** FileBrowser 2.0 changes the config format and the database. This add-on converts both automatically, but you should first create a Home Assistant backup of the add-on, or copy `/addon_configs/*filebrowser_quantum*/` (`config.yaml` and `database.db`). Your 1.x `database.db` is left untouched, but downgrading after the migration loses any changes made in 2.0.
- Fix startup on 2.0.0, for fresh installs and upgrades (#3109).
- The add-on now writes the v2 config format: `http.port`, `http.listen`, `http.baseURL` and `server.database.path`.
- The deprecated `FILEBROWSER_DATABASE` variable is dropped.
- Upgrade from 1.x: `/config/config.yaml` is converted in place. A backup is saved as `config.yaml.v1.bak`.
- Keys that 2.0 moved are now under `http:`.
- Keys that 2.0 removed are dropped: `userDefaults`, source `conditionals` and `indexingIntervalMinutes`, rule `fileNames` and `folderNames`, `trustedHeaders` and `exiftoolPath`.
- Everything else is kept, including extra sources and auth/OIDC settings.
- Users, shares and settings in `/config/database.db` are migrated to `/config/database.sqlite` on first start.
- `http.trustProxyHeaders` is set to `true`, because the add-on always runs behind nginx on a subpath.
- The container healthcheck now checks FileBrowser directly on port 8080 instead of an nginx stub.
- Direct access on port 8071 no longer passes on a client-supplied `X-Forwarded-For`, so the IP-based login lockout cannot be bypassed now that proxy headers are trusted. Ingress keeps the forwarded chain.
## 2.0.0 (2026-10-10)
- Update to latest version from gtsteffaniak/filebrowser (changelog : https://github.com/gtsteffaniak/filebrowser/releases)
- Local disks: `localdisks` can now mount a single folder of a disk with `disk/folder` (e.g. `sda1/public` or `NAS/public`, mounted at `/mnt/<disk>/<folder>`). Existing values are unchanged.
+1 -1
View File
@@ -116,4 +116,4 @@ LABEL \
#################
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
CMD curl -f http://localhost:3001/health || exit 1
CMD curl -fs -o /dev/null http://localhost:8080/ || exit 1
+1 -2
View File
@@ -74,7 +74,6 @@ devices:
environment:
FB_BASEURL: /filebrowser_quantum
FILEBROWSER_CONFIG: "/config/config.yaml"
FILEBROWSER_DATABASE: "/config/database.db"
PGID: "0"
PUID: "0"
image: ghcr.io/alexbelgium/filebrowser_quantum-{arch}
@@ -118,4 +117,4 @@ schema:
slug: filebrowser_quantum
udev: true
url: https://github.com/alexbelgium/hassio-addons
version: "2.0.0"
version: "2.0.0.2"
@@ -79,6 +79,21 @@ mkdir -p /var/log/nginx && touch /var/log/nginx/error.log
mkdir -p /config /cache
# 1.x config (string server.database): both versions reject unknown keys, so
# move or drop the keys 2.0 removed and keep everything else (users and shares
# are in the database, imported below)
if [ -f "$FILEBROWSER_CONFIG" ] && [ "$(yq e '.server.database | tag' "$FILEBROWSER_CONFIG")" = "!!str" ]; then
bashio::log.warning "Converting FileBrowser 1.x config to 2.0, backup saved to ${FILEBROWSER_CONFIG}.v1.bak"
cp "$FILEBROWSER_CONFIG" "${FILEBROWSER_CONFIG}.v1.bak"
yq e -i '
.http *= (.server | pick(["socket", "tlsCert", "tlsKey", "externalUrl", "internalUrl", "disableWebDAV"])) |
del(.server.database, .server.port, .server.listen, .server.baseURL, .server.socket, .server.tlsCert, .server.tlsKey, .server.externalUrl, .server.internalUrl, .server.disableWebDAV) |
del(.http.trustedHeaders, .integrations.media.exiftoolPath, .userDefaults) |
del(.server.sources[].config.conditionals, .server.sources[].config.indexingIntervalMinutes) |
del(.server.sources[].config.rules[].fileNames, .server.sources[].config.rules[].folderNames)
' "$FILEBROWSER_CONFIG"
fi
# Copy default config if not existing
if [ ! -f "$FILEBROWSER_CONFIG" ]; then
cp /home/filebrowser/data/config.yaml "$FILEBROWSER_CONFIG"
@@ -88,9 +103,14 @@ bashio::log.info "Updating FileBrowser config..."
# --- Server (hardcoded values) ---
bashio::log.info "... set server"
yq e -i ".server.port = 8080" "$FILEBROWSER_CONFIG"
yq e -i ".server.listen = \"0.0.0.0\"" "$FILEBROWSER_CONFIG"
yq e -i ".server.database = \"/config/database.db\"" "$FILEBROWSER_CONFIG"
yq e -i ".http.port = 8080" "$FILEBROWSER_CONFIG"
yq e -i ".http.listen = \"0.0.0.0\"" "$FILEBROWSER_CONFIG"
yq e -i ".http.trustProxyHeaders = true" "$FILEBROWSER_CONFIG"
yq e -i ".server.database.path = \"/config/database.sqlite\" | del(.server.database.migrateFrom)" "$FILEBROWSER_CONFIG"
# Import the 1.x BoltDB until the SQLite database exists
if [ -s /config/database.db ] && [ ! -s /config/database.sqlite ]; then
yq e -i ".server.database.migrateFrom = \"/config/database.db\"" "$FILEBROWSER_CONFIG"
fi
yq e -i ".server.cacheDir = \"/cache\"" "$FILEBROWSER_CONFIG"
# --- Default user scope / source path ---
@@ -117,7 +137,7 @@ yq e -i ".server.sources[0].config.defaultUserScope = \"${DEFAULT_USER_SCOPE}\""
# --- Base URL (from env or config) ---
bashio::log.info "... set base URL to allow ingress"
BASE_URL=$(bashio::config 'base_url' "${FB_BASEURL:-/}")
yq e -i ".server.baseURL = \"${BASE_URL}\"" "$FILEBROWSER_CONFIG"
yq e -i ".http.baseURL = \"${BASE_URL}\"" "$FILEBROWSER_CONFIG"
# --- Auth method ---
AUTH_METHOD=$(bashio::config 'auth_method' 'password')
@@ -10,7 +10,7 @@ proxy_set_header Accept-Encoding "";
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-For $fb_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-NginX-Proxy true;
proxy_set_header X-Real-IP $remote_addr;
@@ -1,3 +1,11 @@
# FileBrowser trusts X-Forwarded-For (http.trustProxyHeaders) for login rate
# limits: keep the chain from the Supervisor ingress proxy, but replace
# whatever a client sends straight to the published port
map $server_port $fb_forwarded_for {
8072 $remote_addr;
default $proxy_add_x_forwarded_for;
}
server {
listen 0.0.0.0:8072 default_server;
@@ -1,8 +0,0 @@
server {
listen 127.0.0.1:3001;
access_log off;
location /health {
return 200 'OK';
}
}
@@ -13,12 +13,12 @@ server {
proxy_read_timeout 30m;
proxy_pass %%protocol%%://backend%%subpath%%;
# Two things the ingress panel needs that a plain browser tab does not.
# Three things the ingress panel needs that a plain browser tab does not.
# Both are injected into the page's existing nonce-carrying inline script
# rather than next to <div id="app">: FileBrowser sends
# script-src 'self' 'nonce-<random>', so a standalone inline <script>
# would be blocked. If upstream ever drops that
# window.__pwaDeferredPrompt line the filter stops matching and both
# window.__pwaDeferredPrompt line the filter stops matching and all three
# behaviours revert, which is the state before either fix.
#
# 1. Opening a folder. The tool views (Tools -> File Size Analyzer and
@@ -106,7 +106,12 @@ server {
# links inside a document FileBrowser renders in its own iframe -- the
# pdf viewer, the srcdoc markdown/html preview, OnlyOffice -- because a
# listener on this document never sees another document's clicks.
sub_filter "window.__pwaDeferredPrompt = null;" "window.__pwaDeferredPrompt = null;(function(){var o=window.open;window.open=function(u,n,f){try{var b=(window.globalVars||{}).baseURL;if(u&&n==='_blank'&&!f&&b){if(b.slice(-1)!=='/')b+='/';var t=new URL(u,location.href);if((t.protocol==='http:'||t.protocol==='https:')&&t.origin===location.origin&&(t.pathname.indexOf(b+'files/')===0||t.pathname.indexOf(b+'public/share/')===0)){location.assign(t.href);return window}}}catch(e){}return o.apply(window,arguments)};document.addEventListener('click',function(e){try{if(e.button||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey)return;var a=e.target&&e.target.closest?e.target.closest('a'):null;if(!a||!a.href)return;var b=(window.globalVars||{}).baseURL;if(!b)return;if(b.slice(-1)!=='/')b+='/';var t=new URL(a.href,location.href);if(t.origin!==location.origin)return;if(!a.hasAttribute('download')&&t.searchParams.get('inline')!=='true'&&(t.pathname===b+'api/resources/download'||t.pathname===b+'public/api/resources/download')){a.download='';a.removeAttribute('target');return}if(a.target==='_blank'&&t.pathname.indexOf(b)===0&&navigator.userAgent.indexOf('Mobile/HomeAssistant')!==-1){a.removeAttribute('target')}}catch(err){}},true)})();";
# 3. The status-bar inset. 2.0 pads its header by env(safe-area-inset-top)
# (--safe-area-top), but inside the Home Assistant app the panel already
# sits below HA's toolbar, which handles that inset, so in portrait it
# was applied twice: an empty band above the search bar. Zero it on
# <html>, which overrides the :root rule; the direct port is untouched.
sub_filter "window.__pwaDeferredPrompt = null;" "window.__pwaDeferredPrompt = null;document.documentElement.style.setProperty('--safe-area-top','0px');(function(){var o=window.open;window.open=function(u,n,f){try{var b=(window.globalVars||{}).baseURL;if(u&&n==='_blank'&&!f&&b){if(b.slice(-1)!=='/')b+='/';var t=new URL(u,location.href);if((t.protocol==='http:'||t.protocol==='https:')&&t.origin===location.origin&&(t.pathname.indexOf(b+'files/')===0||t.pathname.indexOf(b+'public/share/')===0)){location.assign(t.href);return window}}}catch(e){}return o.apply(window,arguments)};document.addEventListener('click',function(e){try{if(e.button||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey)return;var a=e.target&&e.target.closest?e.target.closest('a'):null;if(!a||!a.href)return;var b=(window.globalVars||{}).baseURL;if(!b)return;if(b.slice(-1)!=='/')b+='/';var t=new URL(a.href,location.href);if(t.origin!==location.origin)return;if(!a.hasAttribute('download')&&t.searchParams.get('inline')!=='true'&&(t.pathname===b+'api/resources/download'||t.pathname===b+'public/api/resources/download')){a.download='';a.removeAttribute('target');return}if(a.target==='_blank'&&t.pathname.indexOf(b)===0&&navigator.userAgent.indexOf('Mobile/HomeAssistant')!==-1){a.removeAttribute('target')}}catch(err){}},true)})();";
}
}
+5
View File
@@ -0,0 +1,5 @@
## 3.7.21 (2026-10-11)
- Initial release: Joplin desktop streamed to the browser with Selkies, based on linuxserver/docker-joplin (amd64 only, as Joplin publishes no Linux arm64 build)
- Shares the Selkies startup scripts with the webtop and claude_desktop add-ons (data location, GPU permissions, ingress, SSL)
- Own SSL certificates (`use_own_certs`) now also apply when `data_location` is changed: the shared `90-ssl.sh` replaces whatever certificate path nginx holds instead of a fixed `/config/data/ssl/...` string, and warns instead of reporting success when it cannot
+129
View File
@@ -0,0 +1,129 @@
#============================#
# ALEXBELGIUM'S DOCKERFILE #
#============================#
# _.------.
# _.-` ('>.-`"3.7.21""-.
# '.--'` _'` _ .--.)
# -' '-.-';` `
# ' - _.' ``'--.
# '---` .-'"3.7.21"`
# /`
#=== Home Assistant Addon ===#
#################
# 1 Build Image #
#################
ARG BUILD_FROM
ARG BUILD_VERSION
FROM ${BUILD_FROM}
##################
# 2 Modify Image #
##################
# Set S6 wait time
ENV S6_CMD_WAIT_FOR_SERVICES=1 \
S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
S6_SERVICES_GRACETIME=0
USER root
# load volume
VOLUME [ "/sys/fs/cgroup" ]
# Set shell
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# Allow UID and GID setting
# hadolint ignore=SC2015,DL4006,SC2013,SC2086
RUN \
# Change home folder location
usermod --home /config/data abc && \
\
# Set +e
if [[ -d /etc/services.d ]] && ls /etc/services.d/*/run 1> /dev/null 2>&1; then sed -i "1a set +e" /etc/services.d/*/run; fi
# Global LSIO modifications
COPY ha_lsio.sh /ha_lsio.sh
ARG CONFIGLOCATION="/config/data"
RUN chmod 744 /ha_lsio.sh && if grep -qr "lsio" /etc; then /ha_lsio.sh "$CONFIGLOCATION"; fi && rm /ha_lsio.sh
##################
# 3 Install apps #
##################
# Add rootfs
COPY rootfs/ /
RUN find . -type f \( -name "*.sh" -o -name "run" -o -name "finish" \) -print -exec chmod +x {} \;
# Uses /bin for compatibility purposes
# hadolint ignore=DL4005
RUN if [ ! -f /bin/sh ] && [ -f /usr/bin/sh ]; then ln -s /usr/bin/sh /bin/sh; fi && \
if [ ! -f /bin/bash ] && [ -f /usr/bin/bash ]; then ln -s /usr/bin/bash /bin/bash; fi
# Modules
ARG MODULES="00-banner.sh 01-custom_script.sh 00-local_mounts.sh 00-smb_mounts.sh 90-dns_set.sh"
# Automatic modules download
COPY ha_automodules.sh /ha_automodules.sh
RUN chmod 744 /ha_automodules.sh && /ha_automodules.sh "$MODULES" && rm /ha_automodules.sh
# Manual apps
ENV PACKAGES="nginx"
# Automatic apps & bashio
COPY ha_autoapps.sh /ha_autoapps.sh
RUN chmod 744 /ha_autoapps.sh && /ha_autoapps.sh "$PACKAGES" && rm /ha_autoapps.sh
################
# 4 Entrypoint #
################
# Add entrypoint
#ENV S6_STAGE2_HOOK=/ha_entrypoint.sh
COPY ha_entrypoint.sh /ha_entrypoint.sh
RUN chmod 777 /ha_entrypoint.sh
# Install bashio
COPY bashio-standalone.sh /usr/local/lib/bashio-standalone.sh
RUN chmod 0755 /usr/local/lib/bashio-standalone.sh
#WORKDIR /
ENTRYPOINT [ "/usr/bin/env" ]
CMD [ "/ha_entrypoint.sh" ]
############
# 5 Labels #
############
ARG BUILD_ARCH
ARG BUILD_DATE
ARG BUILD_DESCRIPTION
ARG BUILD_NAME
ARG BUILD_REF
ARG BUILD_REPOSITORY
ARG BUILD_VERSION
ENV BUILD_VERSION="${BUILD_VERSION}"
LABEL \
io.hass.name="${BUILD_NAME}" \
io.hass.description="${BUILD_DESCRIPTION}" \
io.hass.arch="${BUILD_ARCH}" \
io.hass.type="addon" \
io.hass.version=${BUILD_VERSION} \
maintainer="alexbelgium (https://github.com/alexbelgium)" \
org.opencontainers.image.title="${BUILD_NAME}" \
org.opencontainers.image.description="${BUILD_DESCRIPTION}" \
org.opencontainers.image.vendor="Home Assistant Add-ons" \
org.opencontainers.image.authors="alexbelgium (https://github.com/alexbelgium)" \
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.url="https://github.com/alexbelgium" \
org.opencontainers.image.source="https://github.com/${BUILD_REPOSITORY}" \
org.opencontainers.image.documentation="https://github.com/${BUILD_REPOSITORY}/blob/main/README.md" \
org.opencontainers.image.created=${BUILD_DATE} \
org.opencontainers.image.revision=${BUILD_REF} \
org.opencontainers.image.version=${BUILD_VERSION}
####################
# 6 HealthcheckNOT #
####################
+97
View File
@@ -0,0 +1,97 @@
# Home assistant add-on: Joplin Desktop
I maintain this and other Home Assistant add-ons in my free time: keeping up with upstream changes, HA changes, and testing on real hardware takes a lot of time (and some money). I use around 5-10 of my >110 addons so regularly I install test machines (and purchase some test services such as vpn) that I don't use myself to troubleshoot and improve the addons
If this add-on saves you time or makes your setup easier, I would be very grateful for your support!
[![Buy me a coffee][donation-badge]](https://www.buymeacoffee.com/alexbelgium)
[![Donate via PayPal][paypal-badge]](https://www.paypal.com/donate/?hosted_button_id=DZFULJZTP3UQA)
## Addon informations
![Version](https://img.shields.io/badge/dynamic/yaml?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fjoplin_desktop%2Fconfig.yaml)
![Ingress](https://img.shields.io/badge/dynamic/yaml?label=Ingress&query=%24.ingress&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fjoplin_desktop%2Fconfig.yaml)
![Arch](https://img.shields.io/badge/dynamic/yaml?color=success&label=Arch&query=%24.arch&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fjoplin_desktop%2Fconfig.yaml)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/9c6cf10bdbba45ecb202d7f579b5be0e)](https://www.codacy.com/gh/alexbelgium/hassio-addons/dashboard?utm_source=github.com&utm_medium=referral&utm_content=alexbelgium/hassio-addons&utm_campaign=Badge_Grade)
[![GitHub Super-Linter](https://img.shields.io/github/actions/workflow/status/alexbelgium/hassio-addons/weekly-supelinter.yaml?label=Lint%20code%20base)](https://github.com/alexbelgium/hassio-addons/actions/workflows/weekly-supelinter.yaml)
[![Builder](https://img.shields.io/github/actions/workflow/status/alexbelgium/hassio-addons/onpush_builder.yaml?label=Builder)](https://github.com/alexbelgium/hassio-addons/actions/workflows/onpush_builder.yaml)
[donation-badge]: https://img.shields.io/badge/Buy%20me%20a%20coffee-%23d32f2f?logo=buy-me-a-coffee&style=flat&logoColor=white
[paypal-badge]: https://img.shields.io/badge/Donate%20via%20PayPal-0070BA?logo=paypal&style=flat&logoColor=white
_Thanks to everyone having starred my repo! To star it click on the image below, then it will be on top right. Thanks!_
[![Stargazers repo roster for @alexbelgium/hassio-addons](https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.github/stars2.svg)](https://github.com/alexbelgium/hassio-addons/stargazers)
![downloads evolution](https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/joplin_desktop/stats.png)
## About
[Joplin](https://joplinapp.org) is an open source note-taking and to-do application. This add-on runs the full Joplin **desktop** app and streams it to your browser with Selkies, so you can use it from any device without installing anything.
This addon is based on the docker image <https://github.com/linuxserver/docker-joplin>
If you only need to sync your notes between your own Joplin apps, the [Joplin Server](https://github.com/alexbelgium/hassio-addons/tree/master/joplin) add-on is lighter. The two work together: point this desktop app at your Joplin Server in Joplin's synchronisation settings.
Only amd64 is supported, because Joplin does not publish a Linux arm64 build.
## Configuration
The recommended way in is ingress (the sidebar panel). You can also enable the https port 3001 in the add-on network settings and open <https://homeassistant:3001>; the browser streaming features need HTTPS, so do not use the plain http port 3000 directly — it is only meant to sit behind your own TLS reverse proxy. If you open a port, set `PASSWORD`: the web interface then asks for user `abc` and that password. This basic authentication is only suitable on a trusted local network; for access from the internet use a reverse proxy with stronger authentication.
Joplin's profile (notes, settings, plugins) is stored in `data_location`, by default `/config/data`, which is the add-on's own folder under `/addon_configs/` on your Home Assistant host. It is kept across restarts and updates and included in backups.
Use the add-on `env_vars` option to pass extra environment variables (uppercase or lowercase names). See <https://github.com/alexbelgium/hassio-addons/wiki/Add-Environment-variables-to-your-Addon-2> for details.
```yaml
PUID: 1000 # user id of the desktop user and owner of the data folder
PGID: 1000 # group id of the desktop user
TZ: Europe/Paris # timezone, Country/City according to https://manpages.ubuntu.com/manpages/trusty/man3/DateTime::TimeZone::Catalog.3pm.html
KEYBOARD: fr-fr-azerty # keyboard layout
PASSWORD: "mypassword" # basic authentication on the web interface (user abc). Set it if you open port 3001; trusted local networks only
DRINODE: /dev/dri/renderD128 # GPU device used for rendering and encoding, if the default does not work
data_location: /config/data # where Joplin's profile is stored; must be in /config, /share, /data or /mnt
additional_apps: "" # comma-separated apt packages to install at every start (not persistent otherwise)
use_own_certs: false # use your own certificates from /ssl for the https port 3001
certfile: fullchain.pem # certificate file in /ssl
keyfile: privkey.pem # key file in /ssl
DNS_server: 8.8.8.8 # keep blank to use your router's DNS
localdisks: sda1 # put the hardware name of your drive to mount separated by commas, or its label. ex. sda1, sdb1, MYNAS... Add a folder to mount only it, ex. MYNAS/public mounts at /mnt/MYNAS/public
networkdisks: "//SERVER/SHARE" # optional, list of smb servers to mount, separated by commas
cifsusername: "username" # optional, smb username, same for all smb shares
cifspassword: "password" # optional, smb password
cifsdomain: "domain" # optional, allow setting the domain for the smb share
```
### Useful upstream variables
These are read by the LinuxServer Selkies base image and can be set through `env_vars`. The full list is at <https://docs.linuxserver.io/images/docker-joplin>.
| Variable | Effect |
| --- | --- |
| `RESTART_APP` | `true` restarts Joplin automatically if its window is closed |
| `NO_DECOR` | any value removes window decorations, so Joplin fills the browser like a web app |
| `NO_FULL` | any value stops the window manager from maximising the window |
| `HARDEN_DESKTOP` | `true` disables the terminal, sudo, xdg-open and Selkies file transfers, keeping only Joplin |
| `SELKIES_AUDIO_ENABLED`, `SELKIES_MICROPHONE_ENABLED` | `false` disables audio or microphone streaming |
| `SELKIES_FRAMERATE` | streaming frame rate cap, e.g. `30` |
## Installation
The installation of this add-on is pretty straightforward and not different in comparison to installing any other add-on.
1. Add my add-ons repository to your home assistant instance (in supervisor addons store at top right, or click button below if you have configured my HA)
[![Open your Home Assistant instance and show the add add-on repository dialog with a specific repository URL pre-filled.](https://my.home-assistant.io/badges/supervisor_add_addon_repository.svg)](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Falexbelgium%2Fhassio-addons)
1. Install this add-on.
1. Click the `Save` button to store your configuration.
1. Set the add-on options to your preferences
1. Start the add-on.
1. Check the logs of the add-on to see if everything went well.
1. Open the webUI and adapt the software options
## Support
Create an issue on github
+72
View File
@@ -0,0 +1,72 @@
#include <tunables/global>
profile joplin_desktop_addon flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
capability chown,
capability dac_override,
capability dac_read_search,
capability fowner,
capability setgid,
capability setuid,
capability sys_chroot,
capability sys_admin,
file,
signal,
mount,
umount,
remount,
network udp,
network tcp,
network dgram,
network stream,
network inet,
network inet6,
network netlink raw,
network unix dgram,
# S6-Overlay
/init ix,
/run/{s6,s6-rc*,service}/** ix,
/package/** ix,
/command/** ix,
/run/{,**} rwk,
/dev/tty rw,
/bin/** ix,
/usr/bin/** ix,
/usr/lib/bashio/** ix,
/etc/s6/** rix,
/run/s6/** rix,
/etc/services.d/** rwix,
/etc/cont-init.d/** rwix,
/etc/cont-finish.d/** rwix,
/init rix,
/var/run/** mrwkl,
/var/run/ mrwkl,
/dev/i2c-1 mrwkl,
# Files required
/dev/fuse mrwkl,
/dev/sda1 mrwkl,
/dev/sdb1 mrwkl,
/dev/nvme0 mrwkl,
/dev/nvme0n1 mrwkl,
/dev/nvme1 mrwkl,
/dev/mmcblk0p1 mrwkl,
/dev/* mrwkl,
/udev/* mrwkl,
/tmp/** mrkwl,
/dev/fuse/** mrkwl,
/dev/** mrkwl,
/sys/firmware/** mrkwl,
# Data access
/data/** rw,
# suppress ptrace denials when using 'docker ps' or using 'ps' inside a container
ptrace (trace,read) peer=docker-default,
# docker daemon confinement requires explict allow rule for signal
signal (receive) set=(kill,term) peer=/usr/bin/docker,
}
+5
View File
@@ -0,0 +1,5 @@
{
"build_from": {
"amd64": "lscr.io/linuxserver/joplin:latest"
}
}
+107
View File
@@ -0,0 +1,107 @@
arch:
- amd64
audio: true
description: Joplin desktop note-taking app accessible via any modern web browser
devices:
- /dev/dri
- /dev/dri/card0
- /dev/dri/card1
- /dev/dri/renderD128
- /dev/sda
- /dev/sdb
- /dev/sdc
- /dev/sdd
- /dev/sde
- /dev/sdf
- /dev/sdg
- /dev/nvme
- /dev/nvme0
- /dev/nvme0n1
- /dev/nvme0n1p1
- /dev/nvme0n1p2
- /dev/mmcblk
- /dev/sda1
- /dev/sdb1
- /dev/sdc1
- /dev/sdd1
- /dev/sde1
- /dev/sdf1
- /dev/sdg1
- /dev/sda2
- /dev/sdb2
- /dev/sdc2
- /dev/sdd2
- /dev/sde2
- /dev/sdf2
- /dev/sdg2
- /dev/sda3
- /dev/sdb3
- /dev/sda4
- /dev/sdb4
- /dev/sda5
- /dev/sda6
- /dev/sda7
- /dev/sda8
- /dev/nvme1
- /dev/nvme2
environment:
FM_HOME: /config/data
HOME: /config/data
START_DOCKER: "false"
TITLE: Joplin
image: ghcr.io/alexbelgium/joplin_desktop-{arch}
ingress: true
init: false
map:
- app_config:rw
- media:rw
- share:rw
- ssl
name: Joplin Desktop
options:
env_vars: []
DNS_server: 8.8.8.8
PGID: 1000
PUID: 1000
additional_apps: ""
certfile: fullchain.pem
data_location: /config/data
keyfile: privkey.pem
use_own_certs: false
panel_admin: false
panel_icon: mdi:notebook-edit
ports:
3000/tcp: null
3001/tcp: null
ports_description:
3000/tcp: Web interface (http)
3001/tcp: Web interface (https)
privileged:
- SYS_ADMIN
- DAC_READ_SEARCH
schema:
env_vars:
- name: match(^[A-Za-z0-9_]+$)
value: str?
DNS_server: str?
DRINODE: list(/dev/dri/card0|/dev/dri/card1|/dev/dri/card2|/dev/dri/renderD128|/dev/dri/renderD129|)?
KEYBOARD: list(da-dk-qwerty|de-de-qwertz|en-gb-qwerty|en-us-qwerty|es-es-qwerty|fr-ch-qwertz|fr-fr-azerty|it-it-qwerty|ja-jp-qwerty|pt-br-qwerty|sv-se-qwerty|tr-tr-qwerty)?
PASSWORD: password?
PGID: int
PUID: int
TZ: match([A-Z][a-z]*./[A-Z][a-z]*.)?
additional_apps: str?
certfile: str
cifsdomain: str?
cifspassword: password?
cifsusername: str?
data_location: str?
keyfile: str
localdisks: str?
networkdisks: str?
use_own_certs: bool?
slug: joplin_desktop
udev: true
url: https://github.com/alexbelgium/hassio-addons/tree/master/joplin_desktop
version: "3.7.21"
video: true
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

+1
View File
@@ -0,0 +1 @@
../../../../claude_desktop/rootfs/etc/cont-init.d/20-folders.sh
@@ -0,0 +1 @@
../../../../claude_desktop/rootfs/etc/cont-init.d/21-gpu_permissions.sh
@@ -0,0 +1 @@
../../../../claude_desktop/rootfs/etc/cont-init.d/80-configuration.sh
+1
View File
@@ -0,0 +1 @@
../../../../claude_desktop/rootfs/etc/cont-init.d/90-ingress.sh
+1
View File
@@ -0,0 +1 @@
../../../../webtop_kde/rootfs/etc/cont-init.d/90-ssl.sh
+1
View File
@@ -0,0 +1 @@
../../../../../claude_desktop/rootfs/etc/nginx/includes/mime.types
@@ -0,0 +1 @@
../../../../../claude_desktop/rootfs/etc/nginx/includes/proxy_params.conf
@@ -0,0 +1 @@
../../../../../claude_desktop/rootfs/etc/nginx/includes/resolver.conf
@@ -0,0 +1 @@
../../../../../claude_desktop/rootfs/etc/nginx/includes/server_params.conf
@@ -0,0 +1 @@
../../../../../claude_desktop/rootfs/etc/nginx/includes/ssl_params.conf
@@ -0,0 +1 @@
../../../../../claude_desktop/rootfs/etc/nginx/includes/upstream.conf
+9
View File
@@ -0,0 +1,9 @@
{
"github_fulltag": "false",
"last_update": "2026-10-11",
"repository": "alexbelgium/hassio-addons",
"slug": "joplin_desktop",
"source": "github",
"upstream_repo": "linuxserver/docker-joplin",
"upstream_version": "3.7.21"
}
+12 -4
View File
@@ -2,6 +2,8 @@
# shellcheck shell=bash
set -e
# Shared with joplin_desktop (and webtop, through its rootfs symlink); keep it add-on agnostic.
if bashio::config.true 'use_own_certs'; then
bashio::log.green "Using referenced ssl certificates to connect with https. Please remember to open the ssl port in the addon options"
CERTFILE="$(bashio::config 'certfile')"
@@ -11,10 +13,16 @@ if bashio::config.true 'use_own_certs'; then
#Check if files exist
echo "... checking if referenced files exist"
if [ -f /ssl/"$CERTFILE" ] && [ -f /ssl/"$KEYFILE" ]; then
# Add ssl file
sed -i "s|/config/data/ssl/cert.pem|/ssl/$CERTFILE|g" "$NGINX_CONFIG"
sed -i "s|/config/data/ssl/cert.key|/ssl/$KEYFILE|g" "$NGINX_CONFIG"
echo "... done"
# Replace whatever path the directives hold rather than a fixed one: the generated
# certificate lives under the data location, and 20-folders.sh rewrites that path when
# data_location is changed, so a literal /config/data/ssl/... match silently missed.
sed -Ei "s|^([[:space:]]*ssl_certificate[[:space:]]+).*;|\1/ssl/$CERTFILE;|" "$NGINX_CONFIG"
sed -Ei "s|^([[:space:]]*ssl_certificate_key[[:space:]]+).*;|\1/ssl/$KEYFILE;|" "$NGINX_CONFIG"
if grep -q "ssl_certificate[[:space:]]*/ssl/$CERTFILE;" "$NGINX_CONFIG"; then
echo "... done"
else
bashio::log.warning "... could not set /ssl/$CERTFILE in $NGINX_CONFIG, using self-generated certificates"
fi
else
bashio::log.warning "... certificate /ssl/$CERTFILE and /ssl/$KEYFILE and not found, using self-generated certificates"
fi