diff --git a/komga/CHANGELOG.md b/komga/CHANGELOG.md new file mode 100644 index 0000000000..9d205b8cdf --- /dev/null +++ b/komga/CHANGELOG.md @@ -0,0 +1,6 @@ +## 1.26.1 (2026-08-11) + +- Initial release, based on gotson/komga ([changelog](https://github.com/gotson/komga/releases)) +- Ingress support : Komga is served on the `/komga` servlet context path, nginx prefixes it back with the ingress entry +- Supports local disks and SMB network shares for libraries (`localdisks` / `networkdisks` options) +- Supports extra environment variables via the `env_vars` option, see the [documentation](https://github.com/alexbelgium/hassio-addons/wiki/Add-Environment-variables-to-your-Addon-2) diff --git a/komga/Dockerfile b/komga/Dockerfile new file mode 100644 index 0000000000..93e5e90562 --- /dev/null +++ b/komga/Dockerfile @@ -0,0 +1,121 @@ +#============================# +# ALEXBELGIUM'S DOCKERFILE # +#============================# +# _.------. +# _.-` ('>.-`"""-. +# '.--'` _'` _ .--.) +# -' '-.-';` ` +# ' - _.' ``'--. +# '---` .-'""` +# /` +#=== Home Assistant Addon ===# + +################# +# 1 Build Image # +################# + +ARG BUILD_FROM +ARG BUILD_VERSION +ARG BUILD_UPSTREAM="1.26.1" +FROM ${BUILD_FROM} +ENV BASHIO_VERSION=0.14.3 + +################## +# 2 Modify Image # +################## + +# No S6_* tuning here : the upstream image ships no s6-overlay, so the vars the +# other addons set would be read by nobody + +# Komga is served from a fixed servlet context path. Ingress strips its own +# prefix before forwarding, and Komga renders absolute asset urls, so nginx +# needs a stable subpath to prefix back. See rootfs/etc/nginx/servers/ingress.conf +ENV SERVER_SERVLET_CONTEXTPATH="/komga" + +################## +# 3 Install apps # +################## + +# Add rootfs +# Absolute paths on purpose : the upstream image sets WORKDIR /app, so the +# relative "find ." used by the other addons would miss /etc entirely +COPY rootfs/ / +RUN find /etc/cont-init.d /etc/services.d -type f \( -name "*.sh" -o -name "run" \) -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 00-global_var.sh 01-custom_script.sh 00-local_mounts.sh 00-smb_mounts.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 # +################ + +# The upstream image is a plain jre image without s6-overlay, so ha_entrypoint +# runs as pid 1 : it executes /etc/cont-init.d, then supervises /etc/services.d +COPY ha_entrypoint.sh /ha_entrypoint.sh +RUN chmod 777 /ha_entrypoint.sh +ENTRYPOINT ["/ha_entrypoint.sh"] + +# Install bashio +COPY bashio-standalone.sh /usr/local/lib/bashio-standalone.sh +RUN chmod 0755 /usr/local/lib/bashio-standalone.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 Healthcheck # +################# + +# Komga is a jvm app, first boot builds the database : leave it time to settle +ENV HEALTH_PORT="25600" \ + HEALTH_URL="/komga/" +HEALTHCHECK \ + --interval=30s \ + --retries=5 \ + --start-period=180s \ + --timeout=25s \ + CMD curl -A "HealthCheck: Docker/1.0" -s -f "http://127.0.0.1:${HEALTH_PORT}${HEALTH_URL}" >/dev/null 2>&1 || exit 1 diff --git a/komga/README.md b/komga/README.md new file mode 100644 index 0000000000..bcb67e8fde --- /dev/null +++ b/komga/README.md @@ -0,0 +1,70 @@ +# Home Assistant Add-on: Komga + +Free and open source comics/mangas media server. + +[Komga](https://komga.org) organizes your comics, mangas, BDs, magazines and ebooks, serves them +through a web reader, and exposes OPDS, Kobo sync and a REST API for third-party readers +(Tachiyomi/Mihon, Panels, Chunky, ...). + +## About + +- Browse and read CBZ, CBR, PDF and EPUB files from any browser +- Import metadata, edit series/books, build collections and read lists +- Multi-user, with per-user library restrictions and age ratings +- OPDS v1/v2, Kobo sync, and a documented REST API + +## Installation + +1. Add this repository to Home Assistant. +2. Install the **Komga** add-on. +3. Start the add-on and open it from the sidebar (ingress), or on port `25600` at + `http://homeassistant:25600/komga`. +4. Create the initial user account when the web interface asks for it. +5. Add a library pointing at your comics, for example `/media/comics` or `/share/comics`. + +The first start takes longer than usual: Komga is a JVM application and builds its database and +search index on first boot. + +## Configuration + +| Option | Description | +|--------|-------------| +| `PUID` / `PGID` | Ownership applied to the add-on configuration directory. Defaults to `0` (root). | +| `TZ` | Timezone, e.g. `Europe/Paris`. | +| `localdisks` | Local disks to mount, e.g. `sda1` or a disk label. | +| `networkdisks` | SMB shares to mount, e.g. `//192.168.1.2/comics`. Mounted under `/mnt`. | +| `cifsusername` / `cifspassword` / `cifsdomain` | Credentials for the SMB shares. | +| `smbv1` | Allow the legacy SMBv1 protocol. | +| `env_vars` | Extra environment variables passed to Komga. See the [wiki](https://github.com/alexbelgium/hassio-addons/wiki/Add-Environment-variables-to-your-Addon-2). | + +Most Komga settings can be passed through `env_vars` using the upstream naming, see the +[Komga configuration options](https://komga.org/docs/installation/configuration/). A common one: + +- `JAVA_TOOL_OPTIONS` = `-Xmx1g` — cap the JVM heap on small machines. + +`SERVER_SERVLET_CONTEXTPATH` and `SERVER_PORT` are reserved by the add-on: ingress is built +around the `/komga` path on port 25600, and overriding either breaks the sidebar panel. + +## Ingress and URLs + +Komga is served from the `/komga` subpath so that it works behind Home Assistant ingress: + +- from the Home Assistant sidebar: ingress, no extra setup +- directly: `http://homeassistant:25600/komga` + +External clients — OPDS readers, Kobo sync, Tachiyomi/Mihon, Panels — must use the direct +`http://homeassistant:25600/komga` url. Ingress is browser-session based, so those clients cannot +authenticate through it. + + +## Data + +Komga's database, logs and search index live in `/config` inside the add-on, which Home Assistant +maps to this add-on's own configuration directory — `/addon_configs/_komga`, browsable +with the Filebrowser add-on. They survive add-on updates. Libraries stay where you put them, under +`/media`, `/share` or a mounted disk. + +## Support + +- [Komga upstream project](https://github.com/gotson/komga) +- [Add-on repository issues](https://github.com/alexbelgium/hassio-addons/issues) diff --git a/komga/build.json b/komga/build.json new file mode 100644 index 0000000000..492bb31e52 --- /dev/null +++ b/komga/build.json @@ -0,0 +1,6 @@ +{ + "build_from": { + "aarch64": "gotson/komga:1.26.1", + "amd64": "gotson/komga:1.26.1" + } +} diff --git a/komga/config.yaml b/komga/config.yaml new file mode 100644 index 0000000000..4c4bb0a0d2 --- /dev/null +++ b/komga/config.yaml @@ -0,0 +1,104 @@ +arch: + - aarch64 + - amd64 +description: Free and open source comics/mangas media server +devices: + - /dev/dri + - /dev/dri/card0 + - /dev/dri/card1 + - /dev/dri/renderD128 + - /dev/vchiq + - /dev/video10 + - /dev/video11 + - /dev/video12 + - /dev/video13 + - /dev/video14 + - /dev/video15 + - /dev/video16 + - /dev/ttyUSB0 + - /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/nvme0n1p3 + - /dev/nvme1n1 + - /dev/nvme1n1p1 + - /dev/nvme1n1p2 + - /dev/nvme1n1p3 + - /dev/nvme2n1 + - /dev/nvme2n1p1 + - /dev/nvme2n1p2 + - /dev/nvme2n3p3 + - /dev/mmcblk + - /dev/fuse + - /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/nvme0 + - /dev/nvme1 + - /dev/nvme2 +image: ghcr.io/alexbelgium/komga-{arch} +ingress: true +ingress_entry: komga +init: false +map: + - addon_config:rw + - media:rw + - share:rw +name: Komga +options: + env_vars: [] + PGID: 0 + PUID: 0 +panel_icon: mdi:book-open-page-variant +ports: + 25600/tcp: 25600 +ports_description: + 25600/tcp: Web interface (path /komga) +privileged: + - SYS_ADMIN + - DAC_READ_SEARCH +schema: + env_vars: + - name: match(^[A-Za-z0-9_]+$) + value: str? + PGID: int + PUID: int + TZ: str? + cifsdomain: str? + cifspassword: str? + cifsusername: str? + localdisks: str? + networkdisks: str? + smbv1: bool? +slug: komga +udev: true +url: https://github.com/alexbelgium/hassio-addons/tree/master/komga +version: "1.26.1" diff --git a/komga/icon.png b/komga/icon.png new file mode 100644 index 0000000000..11d12f77d4 Binary files /dev/null and b/komga/icon.png differ diff --git a/komga/logo.png b/komga/logo.png new file mode 100644 index 0000000000..71d3b91bd7 Binary files /dev/null and b/komga/logo.png differ diff --git a/komga/rootfs/etc/cont-init.d/20-config_location.sh b/komga/rootfs/etc/cont-init.d/20-config_location.sh new file mode 100755 index 0000000000..d73cfd589a --- /dev/null +++ b/komga/rootfs/etc/cont-init.d/20-config_location.sh @@ -0,0 +1,15 @@ +#!/usr/bin/with-contenv bashio +# shellcheck shell=bash +set -e + +# Komga stores its database, logs and search index in KOMGA_CONFIGDIR, which the +# upstream image sets to /config -- that is the addon_config mount + +CONFIG_LOCATION="/config" +bashio::log.info "Config stored in $CONFIG_LOCATION" + +mkdir -p "$CONFIG_LOCATION" +# Numbered 20- on purpose : it must sort after 00-global_var.sh, which is what +# exports PUID/PGID from the addon options. The upstream image sets neither, so +# the fallbacks only apply when the module is absent. +chown -R "${PUID:-0}:${PGID:-0}" "$CONFIG_LOCATION" diff --git a/komga/rootfs/etc/cont-init.d/32-nginx_ingress.sh b/komga/rootfs/etc/cont-init.d/32-nginx_ingress.sh new file mode 100755 index 0000000000..175e665b40 --- /dev/null +++ b/komga/rootfs/etc/cont-init.d/32-nginx_ingress.sh @@ -0,0 +1,17 @@ +#!/usr/bin/with-contenv bashio +# shellcheck shell=bash +set -e + +################# +# NGINX SETTING # +################# +declare ingress_interface +declare ingress_port +declare ingress_entry + +ingress_port=$(bashio::addon.ingress_port) +ingress_interface=$(bashio::addon.ip_address) +ingress_entry=$(bashio::addon.ingress_entry) +sed -i "s/%%port%%/${ingress_port}/g" /etc/nginx/servers/ingress.conf +sed -i "s/%%interface%%/${ingress_interface}/g" /etc/nginx/servers/ingress.conf +sed -i "s|%%ingress_entry%%|${ingress_entry}|g" /etc/nginx/servers/ingress.conf diff --git a/komga/rootfs/etc/nginx/includes/mime.types b/komga/rootfs/etc/nginx/includes/mime.types new file mode 100644 index 0000000000..7c7cdef2d1 --- /dev/null +++ b/komga/rootfs/etc/nginx/includes/mime.types @@ -0,0 +1,96 @@ +types { + text/html html htm shtml; + text/css css; + text/xml xml; + image/gif gif; + image/jpeg jpeg jpg; + application/javascript js; + application/atom+xml atom; + application/rss+xml rss; + + text/mathml mml; + text/plain txt; + text/vnd.sun.j2me.app-descriptor jad; + text/vnd.wap.wml wml; + text/x-component htc; + + image/png png; + image/svg+xml svg svgz; + image/tiff tif tiff; + image/vnd.wap.wbmp wbmp; + image/webp webp; + image/x-icon ico; + image/x-jng jng; + image/x-ms-bmp bmp; + + font/woff woff; + font/woff2 woff2; + + application/java-archive jar war ear; + application/json json; + application/mac-binhex40 hqx; + application/msword doc; + application/pdf pdf; + application/postscript ps eps ai; + application/rtf rtf; + application/vnd.apple.mpegurl m3u8; + application/vnd.google-earth.kml+xml kml; + application/vnd.google-earth.kmz kmz; + application/vnd.ms-excel xls; + application/vnd.ms-fontobject eot; + application/vnd.ms-powerpoint ppt; + application/vnd.oasis.opendocument.graphics odg; + application/vnd.oasis.opendocument.presentation odp; + application/vnd.oasis.opendocument.spreadsheet ods; + application/vnd.oasis.opendocument.text odt; + application/vnd.openxmlformats-officedocument.presentationml.presentation + pptx; + application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + xlsx; + application/vnd.openxmlformats-officedocument.wordprocessingml.document + docx; + application/vnd.wap.wmlc wmlc; + application/x-7z-compressed 7z; + application/x-cocoa cco; + application/x-java-archive-diff jardiff; + application/x-java-jnlp-file jnlp; + application/x-makeself run; + application/x-perl pl pm; + application/x-pilot prc pdb; + application/x-rar-compressed rar; + application/x-redhat-package-manager rpm; + application/x-sea sea; + application/x-shockwave-flash swf; + application/x-stuffit sit; + application/x-tcl tcl tk; + application/x-x509-ca-cert der pem crt; + application/x-xpinstall xpi; + application/xhtml+xml xhtml; + application/xspf+xml xspf; + application/zip zip; + + application/octet-stream bin exe dll; + application/octet-stream deb; + application/octet-stream dmg; + application/octet-stream iso img; + application/octet-stream msi msp msm; + + audio/midi mid midi kar; + audio/mpeg mp3; + audio/ogg ogg; + audio/x-m4a m4a; + audio/x-realaudio ra; + + video/3gpp 3gpp 3gp; + video/mp2t ts; + video/mp4 mp4; + video/mpeg mpeg mpg; + video/quicktime mov; + video/webm webm; + video/x-flv flv; + video/x-m4v m4v; + video/x-mng mng; + video/x-ms-asf asx asf; + video/x-ms-wmv wmv; + video/x-msvideo avi; +} diff --git a/komga/rootfs/etc/nginx/includes/resolver.conf b/komga/rootfs/etc/nginx/includes/resolver.conf new file mode 100644 index 0000000000..70f4982b9b --- /dev/null +++ b/komga/rootfs/etc/nginx/includes/resolver.conf @@ -0,0 +1 @@ +resolver 127.0.0.11 ipv6=off; diff --git a/komga/rootfs/etc/nginx/nginx.conf b/komga/rootfs/etc/nginx/nginx.conf new file mode 100644 index 0000000000..2ffda7816e --- /dev/null +++ b/komga/rootfs/etc/nginx/nginx.conf @@ -0,0 +1,56 @@ + +# Run nginx in foreground. +daemon off; + +# This is run inside Docker. +user root; + +# Pid storage location. +pid /var/run/nginx.pid; + +# Set number of worker processes. +worker_processes 1; + +# Enables the use of JIT for regular expressions to speed-up their processing. +pcre_jit on; + +# Write error log to Hass.io add-on log. +error_log /proc/1/fd/1 error; + +# Load allowed environment vars +env HASSIO_TOKEN; + +# Load dynamic modules. +include /etc/nginx/modules-enabled/*.conf; + +# Max num of simultaneous connections by a worker process. +events { + worker_connections 512; +} + +http { + include /etc/nginx/includes/mime.types; + + log_format hassio '[$time_local] $status ' + '$http_x_forwarded_for($remote_addr) ' + '$request ($http_user_agent)'; + + access_log /proc/1/fd/1 hassio; + client_max_body_size 4G; + default_type application/octet-stream; + gzip on; + keepalive_timeout 65; + sendfile on; + server_tokens off; + tcp_nodelay on; + tcp_nopush on; + + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + + include /etc/nginx/includes/resolver.conf; + + include /etc/nginx/servers/*.conf; +} diff --git a/komga/rootfs/etc/nginx/servers/ingress.conf b/komga/rootfs/etc/nginx/servers/ingress.conf new file mode 100644 index 0000000000..53c36d9189 --- /dev/null +++ b/komga/rootfs/etc/nginx/servers/ingress.conf @@ -0,0 +1,60 @@ +server { + listen %%interface%%:%%port%% default_server; + + client_max_body_size 0; + + # Home Assistant opens the ingress panel at / and forwards it + # as / , but Komga only answers below its servlet context path (/komga), so + # bounce the panel there. absolute_redirect off keeps the Location relative + # to the HA host instead of nginx's own listen address. + location = / { + absolute_redirect off; + return 302 %%ingress_entry%%/komga/; + } + + location / { + add_header Access-Control-Allow-Origin *; + proxy_connect_timeout 30m; + proxy_send_timeout 30m; + proxy_read_timeout 30m; + proxy_pass http://127.0.0.1:25600; + + # Komga pushes live events over SSE (/komga/sse/v1/events), which must + # not be buffered or the UI stops refreshing until the buffer fills + proxy_buffering off; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + + # Spring redirects /komga to /komga/ ; the Location it produces is + # absolute against the upstream address, so rewrite it back onto the + # ingress path (the second rule covers an already relative Location). + absolute_redirect off; + proxy_redirect http://127.0.0.1:25600/ %%ingress_entry%%/; + proxy_redirect / %%ingress_entry%%/; + + # Komga renders its index page with Thymeleaf @{...} link expressions, + # so every asset url and window.resourceBaseUrl carry the context path + # (/komga). Ingress strips its own prefix before forwarding, so the + # browser needs that prefix added back. Only text/html is rewritten + # (the nginx default for sub_filter_types) : the SPA derives its api + # origin and router base from resourceBaseUrl at runtime, so json + # responses and book pages stream through untouched. + proxy_set_header Accept-Encoding ""; + sub_filter_once off; + sub_filter "/komga" "%%ingress_entry%%/komga"; + + # The epub/divina reader fetches a Readium manifest whose links Komga + # builds with ServletUriComponentsBuilder.fromCurrentContextPath(), so + # they are fully absolute against the upstream address nginx talks to + # (http://127.0.0.1:25600/komga). Rewriting them to a root relative + # ingress path also fixes the scheme : Home Assistant may be served over + # https, and an absolute http:// link would be blocked as mixed content. + # Only the json/xml document types are added here, so book pages are + # never scanned. + sub_filter "http://127.0.0.1:25600/komga" "%%ingress_entry%%/komga"; + sub_filter_types application/json application/webpub+json + application/divina+json application/opds+json + application/atom+xml; + } +} diff --git a/komga/rootfs/etc/services.d/komga/run b/komga/rootfs/etc/services.d/komga/run new file mode 100755 index 0000000000..f6b24430da --- /dev/null +++ b/komga/rootfs/etc/services.d/komga/run @@ -0,0 +1,17 @@ +#!/usr/bin/with-contenv bashio +# shellcheck shell=bash +set -e +# ============================================================================== + +# Same invocation as the upstream image entrypoint (gotson/komga), which is +# replaced by ha_entrypoint.sh so that cont-init.d and nginx can run too. +# SERVER_SERVLET_CONTEXTPATH is set in the Dockerfile, see ingress.conf. + +bashio::log.info "Starting Komga (served on the /komga path, see the addon documentation)" + +cd /app +exec java \ + -Dspring.profiles.include=docker \ + --enable-native-access=ALL-UNNAMED \ + -jar application.jar \ + --spring.config.additional-location=file:/config/ diff --git a/komga/rootfs/etc/services.d/nginx/run b/komga/rootfs/etc/services.d/nginx/run new file mode 100755 index 0000000000..c7febdae96 --- /dev/null +++ b/komga/rootfs/etc/services.d/nginx/run @@ -0,0 +1,19 @@ +#!/usr/bin/with-contenv bashio +# shellcheck shell=bash +set -e +# ============================================================================== + +# Wait for komga to answer before nginx starts serving ingress. First boot +# builds the database, so leave a wide margin, but poll rather than call +# bashio::net.wait_for : bashio takes (port host timeout) while the bundled +# bashio-standalone.sh takes (host port timeout), and picking the wrong one +# would either fail instantly or block for the whole timeout. +for _ in $(seq 1 180); do + if curl -sf -o /dev/null "http://127.0.0.1:25600/komga/"; then + break + fi + sleep 5 +done + +bashio::log.info "Starting NGinx..." +exec nginx diff --git a/komga/updater.json b/komga/updater.json new file mode 100644 index 0000000000..cc8e4340fa --- /dev/null +++ b/komga/updater.json @@ -0,0 +1,9 @@ +{ + "github_beta": "false", + "last_update": "2026-08-11", + "repository": "alexbelgium/hassio-addons", + "slug": "komga", + "source": "github", + "upstream_repo": "gotson/komga", + "upstream_version": "1.26.1" +}