mirror of
https://github.com/alexbelgium/hassio-addons.git
synced 2026-09-04 08:53:33 +02:00
feat(comicarr): new add-on for Comicarr with ingress support (#3001)
* feat(comicarr): new add-on with Home Assistant ingress Comicarr is a fork of Mylar3 with a React frontend and a FastAPI backend. The upstream image is a plain python:3.12-slim with no s6-overlay, so ha_entrypoint.sh runs as pid 1 and supervises both the app and nginx — the same shape the komga add-on uses. Ingress needs a reverse proxy because the app has no url-base support of any kind: vite emits absolute /assets urls, the api client and the cover img tags build absolute /api and /cache urls, and SecurityHeadersMiddleware sends X-Frame-Options: DENY together with a CSP carrying frame-ancestors 'none', which alone would leave the panel blank. The bundled nginx rewrites those paths onto the ingress entry, replaces the two framing headers with the same policy narrowed to the Home Assistant origin, scopes the session cookie to the ingress path and drops upstream's one-year immutable caching for the rewritten assets. The app is started directly as root by default rather than through the upstream /entrypoint.sh, which runs useradd -u "$PUID" under set -e and would exit on this repo's PUID=0 default; that entrypoint is still used when the user asks for an unprivileged uid. --port 8090 is forced because the port is writable from the Settings page and changing it there would silently break both the proxy and the health check. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(comicarr): note that switching PUID leaves existing files root-owned Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(comicarr): drop ingress_port, the add-on linter rejects the default 8099 is the Supervisor default, and frenck/action-addon-linter fails with "'ingress_port' should be removed, it uses a default value". komga omits it for the same reason; nginx still binds whatever bashio::addon.ingress_port reports. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(comicarr): 0755 on the entrypoint instead of 777 The rest of the repo uses 777 here, but this add-on is the one that offers a non-root mode: with PUID set, the app runs as an unprivileged user that could otherwise rewrite a file docker executes as root on the next start. Nothing writes to /ha_entrypoint.sh at runtime, so 0755 costs nothing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
3
comicarr/CHANGELOG.md
Normal file
3
comicarr/CHANGELOG.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.34.0 (20-08-2026)
|
||||
- Initial release, based on upstream frankieramirez/comicarr 0.34.0 (changelog : https://github.com/frankieramirez/comicarr/releases)
|
||||
- Home Assistant ingress support through a bundled nginx reverse proxy
|
||||
124
comicarr/Dockerfile
Normal file
124
comicarr/Dockerfile
Normal file
@@ -0,0 +1,124 @@
|
||||
#============================#
|
||||
# ALEXBELGIUM'S DOCKERFILE #
|
||||
#============================#
|
||||
# _.------.
|
||||
# _.-` ('>.-`"""-.
|
||||
# '.--'` _'` _ .--.)
|
||||
# -' '-.-';` `
|
||||
# ' - _.' ``'--.
|
||||
# '---` .-'""`
|
||||
# /`
|
||||
#=== Home Assistant Addon ===#
|
||||
|
||||
#################
|
||||
# 1 Build Image #
|
||||
#################
|
||||
|
||||
ARG BUILD_FROM
|
||||
ARG BUILD_VERSION
|
||||
ARG BUILD_UPSTREAM="0.34.0"
|
||||
FROM ghcr.io/frankieramirez/comicarr:${BUILD_UPSTREAM}
|
||||
|
||||
##################
|
||||
# 2 Modify Image #
|
||||
##################
|
||||
|
||||
USER root
|
||||
|
||||
# No S6_* tuning here : the upstream image is a plain python:3.12-slim with no
|
||||
# s6-overlay, so the vars the other addons set would be read by nobody
|
||||
|
||||
##################
|
||||
# 3 Install apps #
|
||||
##################
|
||||
|
||||
# Add rootfs
|
||||
# Absolute paths on purpose : the upstream image sets WORKDIR /opt/comicarr, 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
|
||||
# Runs before the apps installer on purpose (the repo-wide order) : this script
|
||||
# bootstraps bash, curl and ca-certificates itself, which the slim base lacks,
|
||||
# and the apps installer below decides what to install by grepping the modules
|
||||
# it downloads here
|
||||
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 ships no s6-overlay, so ha_entrypoint runs as pid 1 : it
|
||||
# executes /etc/cont-init.d, then supervises /etc/services.d. This replaces the
|
||||
# upstream /entrypoint.sh, which services.d/comicarr/run still calls when the
|
||||
# user asks for an unprivileged uid.
|
||||
COPY ha_entrypoint.sh /ha_entrypoint.sh
|
||||
RUN chmod 0755 /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 #
|
||||
#################
|
||||
|
||||
# First boot runs the alembic migrations against a cold sqlite database, which
|
||||
# is slow on a low-end arm board : leave it time to settle before failing
|
||||
ENV HEALTH_PORT="8090" \
|
||||
HEALTH_URL="/api/health"
|
||||
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
|
||||
95
comicarr/README.md
Normal file
95
comicarr/README.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# Home Assistant Add-on: Comicarr
|
||||
|
||||
Automated comic book and manga downloader and library manager with a modern React UI.
|
||||
|
||||
[Comicarr](https://comicarr.com) is a fork of Mylar3 rebuilt around a React frontend and a
|
||||
FastAPI backend. You add series, and it watches for new issues, sends them to your download
|
||||
client, tags them and files them into your library.
|
||||
|
||||
## About
|
||||
|
||||
- Track comic series and manga, and grab new issues as they are released
|
||||
- Works with SABnzbd, NZBGet, blackhole and torrent clients
|
||||
- Metadata from ComicVine and Metron, with automatic tagging
|
||||
- One-command migration from an existing Mylar3 installation
|
||||
- OPDS feed for third-party readers
|
||||
|
||||
## Installation
|
||||
|
||||
1. Add this repository to Home Assistant.
|
||||
2. Install the **Comicarr** add-on.
|
||||
3. Start the add-on and open it from the sidebar (ingress), or on port `8090` at
|
||||
`http://homeassistant:8090`.
|
||||
4. Complete the first-run setup when the web interface asks for it.
|
||||
5. Point Comicarr's library and download folders at a persistent location such as
|
||||
`/media/comics` and `/share/downloads`.
|
||||
|
||||
The first start takes longer than usual: the database migrations run against a cold SQLite
|
||||
database.
|
||||
|
||||
## Configuration
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `PUID` / `PGID` | Ownership applied to the add-on configuration directory. Defaults to `0` (root). See the note below before changing it. |
|
||||
| `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 Comicarr. See the [wiki](https://github.com/alexbelgium/hassio-addons/wiki/Add-Environment-variables-to-your-Addon-2). |
|
||||
|
||||
`COMICARR_LOG_LEVEL` (`0`, `1` or `2`) is a useful `env_vars` entry: it overrides the log
|
||||
verbosity chosen in Settings on every restart.
|
||||
|
||||
With the default `PUID`/`PGID` of `0`, Comicarr runs as root, which is what lets it write to
|
||||
Home Assistant's root-owned `/media` and `/share`. Setting `PUID` to any other value hands
|
||||
startup to the upstream entrypoint, which creates a matching user and drops privileges — the
|
||||
library and download folders then have to be writable by that user. Switching an existing
|
||||
installation from `0` to an unprivileged uid also leaves the files already written under
|
||||
`/config/comicarr` owned by root; chown them yourself, or Comicarr will fail the first time it
|
||||
writes its configuration or database.
|
||||
|
||||
The web interface port is fixed at `8090`. Changing **Settings → Interface → port** has no
|
||||
effect: the add-on forces `8090` on startup, because ingress and the health check are built
|
||||
around it.
|
||||
|
||||
## Ingress and URLs
|
||||
|
||||
Comicarr has no url-base setting, so the add-on bundles an nginx reverse proxy that rewrites the
|
||||
absolute `/assets`, `/api` and `/cache` urls in the served HTML, JavaScript and CSS onto the
|
||||
ingress path, and replaces the upstream `X-Frame-Options: DENY` and `frame-ancestors 'none'`
|
||||
headers, which would otherwise leave the panel blank.
|
||||
|
||||
Two consequences worth knowing:
|
||||
|
||||
- The app's client-side router does not know about the ingress prefix. It rewrites the panel's
|
||||
address to `/` shortly after loading. Everything keeps working, because every request url is
|
||||
rewritten to an absolute ingress path — but reloading the panel frame itself (rather than
|
||||
reopening it from the sidebar) shows Home Assistant instead of Comicarr.
|
||||
- Two places in the app navigate with `window.location` rather than the router: finishing the
|
||||
first-run setup, and a session expiring while the dashboard is open. Both leave the panel;
|
||||
reopening Comicarr from the sidebar recovers.
|
||||
|
||||
External clients — OPDS readers in particular — must use the direct `http://homeassistant:8090`
|
||||
url. Ingress is browser-session based, so those clients cannot authenticate through it.
|
||||
|
||||
Do not enable HTTPS inside Comicarr's own settings: the add-on's proxy talks plain HTTP to it on
|
||||
`127.0.0.1`, and ingress would stop working.
|
||||
|
||||
## Data
|
||||
|
||||
Comicarr's `config.ini`, database, logs and cover cache live in `/config/comicarr` inside the
|
||||
add-on, which Home Assistant maps to this add-on's own configuration directory —
|
||||
`/addon_configs/<repository_id>_comicarr`, browsable with the Filebrowser add-on. They survive
|
||||
add-on updates. That is the same layout as the upstream `./config:/config` compose volume, so an
|
||||
existing installation can be copied in as is.
|
||||
|
||||
Comic and download folders are **not** stored there. Point them at `/media`, `/share` or a
|
||||
mounted disk. The `/comics`, `/manga` and `/downloads` paths used by the upstream docker image
|
||||
are not persistent in Home Assistant — do not use them.
|
||||
|
||||
## Support
|
||||
|
||||
- [Comicarr upstream project](https://github.com/frankieramirez/comicarr)
|
||||
- [Add-on repository issues](https://github.com/alexbelgium/hassio-addons/issues)
|
||||
68
comicarr/apparmor.txt
Normal file
68
comicarr/apparmor.txt
Normal file
@@ -0,0 +1,68 @@
|
||||
|
||||
#include <tunables/global>
|
||||
|
||||
profile comicarr_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,
|
||||
|
||||
|
||||
# Entrypoint stack
|
||||
/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/nvme1 mrwkl,
|
||||
/dev/mmcblk0p1 mrwkl,
|
||||
/dev/* mrwkl,
|
||||
/tmp/** 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 explicit allow rule for signal
|
||||
signal (receive) set=(kill,term) peer=/usr/bin/docker,
|
||||
|
||||
}
|
||||
6
comicarr/build.json
Normal file
6
comicarr/build.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"build_from": {
|
||||
"aarch64": "ghcr.io/frankieramirez/comicarr:latest",
|
||||
"amd64": "ghcr.io/frankieramirez/comicarr:latest"
|
||||
}
|
||||
}
|
||||
105
comicarr/config.yaml
Normal file
105
comicarr/config.yaml
Normal file
@@ -0,0 +1,105 @@
|
||||
arch:
|
||||
- aarch64
|
||||
- amd64
|
||||
description:
|
||||
Automated comic book and manga downloader and library manager with a modern
|
||||
React UI
|
||||
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/comicarr-{arch}
|
||||
ingress: true
|
||||
init: false
|
||||
map:
|
||||
- addon_config:rw
|
||||
- media:rw
|
||||
- share:rw
|
||||
name: Comicarr
|
||||
options:
|
||||
env_vars: []
|
||||
PGID: 0
|
||||
PUID: 0
|
||||
panel_icon: mdi:book-open-page-variant
|
||||
ports:
|
||||
8090/tcp: 8090
|
||||
ports_description:
|
||||
8090/tcp: Web interface and OPDS feed
|
||||
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: comicarr
|
||||
udev: true
|
||||
url: https://github.com/alexbelgium/hassio-addons/tree/master/comicarr
|
||||
version: "0.34.0"
|
||||
BIN
comicarr/icon.png
Normal file
BIN
comicarr/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
BIN
comicarr/logo.png
Normal file
BIN
comicarr/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
28
comicarr/rootfs/etc/cont-init.d/20-config_location.sh
Normal file
28
comicarr/rootfs/etc/cont-init.d/20-config_location.sh
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
# Comicarr keeps its config.ini, sqlite database, logs and cover cache in the
|
||||
# datadir it is started with. /config is the addon_config mount, so using
|
||||
# /config/comicarr reproduces the layout of the upstream compose file's
|
||||
# "./config:/config" volume : an existing installation can be copied in as is.
|
||||
|
||||
CONFIG_LOCATION="/config/comicarr"
|
||||
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.
|
||||
# Not recursive : the cover cache under $CONFIG_LOCATION grows to thousands of
|
||||
# files, and walking it on every boot would delay startup for no gain. This is
|
||||
# what the upstream entrypoint does too.
|
||||
chown "${PUID:-0}:${PGID:-0}" /config "$CONFIG_LOCATION"
|
||||
|
||||
# The upstream entrypoint installs the timezone when it runs, and the default
|
||||
# path in services.d/comicarr/run bypasses it, so do it here for both paths.
|
||||
if [ -n "${TZ:-}" ] && [ -f "/usr/share/zoneinfo/${TZ}" ]; then
|
||||
ln -sf "/usr/share/zoneinfo/${TZ}" /etc/localtime
|
||||
echo "${TZ}" > /etc/timezone
|
||||
fi
|
||||
17
comicarr/rootfs/etc/cont-init.d/32-nginx_ingress.sh
Normal file
17
comicarr/rootfs/etc/cont-init.d/32-nginx_ingress.sh
Normal file
@@ -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
|
||||
96
comicarr/rootfs/etc/nginx/includes/mime.types
Normal file
96
comicarr/rootfs/etc/nginx/includes/mime.types
Normal file
@@ -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;
|
||||
}
|
||||
1
comicarr/rootfs/etc/nginx/includes/resolver.conf
Normal file
1
comicarr/rootfs/etc/nginx/includes/resolver.conf
Normal file
@@ -0,0 +1 @@
|
||||
resolver 127.0.0.11 ipv6=off;
|
||||
56
comicarr/rootfs/etc/nginx/nginx.conf
Normal file
56
comicarr/rootfs/etc/nginx/nginx.conf
Normal file
@@ -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;
|
||||
}
|
||||
82
comicarr/rootfs/etc/nginx/servers/ingress.conf
Normal file
82
comicarr/rootfs/etc/nginx/servers/ingress.conf
Normal file
@@ -0,0 +1,82 @@
|
||||
server {
|
||||
listen %%interface%%:%%port%% default_server;
|
||||
|
||||
client_max_body_size 0;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8090;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
|
||||
# The dashboard subscribes to /api/events/stream over SSE ; buffering
|
||||
# would hold every event back until the buffer fills.
|
||||
proxy_buffering off;
|
||||
proxy_connect_timeout 30m;
|
||||
proxy_send_timeout 30m;
|
||||
proxy_read_timeout 30m;
|
||||
|
||||
# Comicarr refuses to be framed : SecurityHeadersMiddleware sends
|
||||
# X-Frame-Options: DENY and a CSP carrying frame-ancestors 'none', which
|
||||
# on their own leave the ingress panel blank. Replace both with the same
|
||||
# policy narrowed to the Home Assistant origin that serves the panel.
|
||||
# The CSP below is upstream's list verbatim except for two directives :
|
||||
# frame-ancestors becomes 'self', and img-src takes any https origin
|
||||
# instead of the metadata-provider allowlist upstream compiles into the
|
||||
# header -- that allowlist grows with upstream releases, and a stale copy
|
||||
# kept here would silently stop covers from loading.
|
||||
proxy_hide_header X-Frame-Options;
|
||||
proxy_hide_header Content-Security-Policy;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'self'; base-uri 'self'; form-action 'self'; object-src 'none'" always;
|
||||
|
||||
# FastAPI's redirect-slash Location headers are built against the address
|
||||
# nginx talks to and carry no ingress prefix ; the second rule covers an
|
||||
# already relative Location.
|
||||
absolute_redirect off;
|
||||
proxy_redirect http://127.0.0.1:8090/ %%ingress_entry%%/;
|
||||
proxy_redirect / %%ingress_entry%%/;
|
||||
|
||||
# Keep the session cookie on the ingress path rather than the Home
|
||||
# Assistant root, so it is not sent to Home Assistant itself nor to any
|
||||
# other add-on's ingress panel. Cookies are matched against the request
|
||||
# path, and every request the app makes is rewritten below to sit under
|
||||
# the ingress entry, so this does not cost the session.
|
||||
proxy_cookie_path / %%ingress_entry%%/;
|
||||
|
||||
# Comicarr has no url-base setting of any kind : vite emits /assets/...
|
||||
# with no base, and the api client, the SSE hook and the cover <img>
|
||||
# tags all build absolute /api/... and /cache/... urls. Ingress strips
|
||||
# its own prefix before forwarding, so the prefix has to be put back
|
||||
# into what the browser sees. Only html (implicit), javascript and css
|
||||
# are scanned -- json responses, cover images and archive bodies stream
|
||||
# through untouched.
|
||||
proxy_set_header Accept-Encoding "";
|
||||
sub_filter_once off;
|
||||
sub_filter_types application/javascript text/javascript text/css;
|
||||
sub_filter '"/assets/' '"%%ingress_entry%%/assets/';
|
||||
sub_filter "'/assets/" "'%%ingress_entry%%/assets/";
|
||||
sub_filter 'url(/assets/' 'url(%%ingress_entry%%/assets/';
|
||||
sub_filter '"/api/' '"%%ingress_entry%%/api/';
|
||||
sub_filter "'/api/" "'%%ingress_entry%%/api/";
|
||||
sub_filter '`/api/' '`%%ingress_entry%%/api/';
|
||||
sub_filter '"/cache/' '"%%ingress_entry%%/cache/';
|
||||
sub_filter "'/cache/" "'%%ingress_entry%%/cache/";
|
||||
sub_filter '`/cache/' '`%%ingress_entry%%/cache/';
|
||||
sub_filter '"/favicon.ico"' '"%%ingress_entry%%/favicon.ico"';
|
||||
|
||||
# Rewritten javascript and css must not be kept under upstream's one
|
||||
# year immutable policy for /assets : those file names are content
|
||||
# hashed upstream, so a change to the rules above would otherwise never
|
||||
# reach a browser that already holds the old transformed bundle. Every
|
||||
# other response is already sent as no-cache by the app, so this
|
||||
# overrides nothing else.
|
||||
proxy_hide_header Cache-Control;
|
||||
add_header Cache-Control "no-cache" always;
|
||||
}
|
||||
}
|
||||
31
comicarr/rootfs/etc/services.d/comicarr/run
Normal file
31
comicarr/rootfs/etc/services.d/comicarr/run
Normal file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
# ==============================================================================
|
||||
|
||||
# The upstream /entrypoint.sh creates a "comicarr" user out of PUID/PGID and
|
||||
# gosu's to it, but it runs "useradd -u $PUID" under set -e : with PUID=0 -- the
|
||||
# default in this repo, and the only value that can write Home Assistant's
|
||||
# root-owned /media and /share -- useradd refuses the duplicate uid and takes
|
||||
# the whole container down. So the default path starts the app directly as root,
|
||||
# the same choice the komga add-on makes, and the upstream entrypoint is used
|
||||
# only when the user asks for an unprivileged uid.
|
||||
#
|
||||
# --port is forced on both paths. HTTP_PORT is writable from the Settings page,
|
||||
# and changing it there would silently break nginx's proxy_pass and the
|
||||
# healthcheck, leaving an add-on that looks healthy and serves nothing.
|
||||
|
||||
umask "${UMASK:-002}"
|
||||
|
||||
if [ "${PUID:-0}" != "0" ]; then
|
||||
bashio::log.info "Starting Comicarr as ${PUID}:${PGID:-0} ..."
|
||||
exec /entrypoint.sh --port 8090
|
||||
fi
|
||||
|
||||
bashio::log.info "Starting Comicarr..."
|
||||
|
||||
cd /opt/comicarr
|
||||
exec python /opt/comicarr/Comicarr.py \
|
||||
--nolaunch \
|
||||
--datadir /config/comicarr \
|
||||
--port 8090
|
||||
35
comicarr/rootfs/etc/services.d/nginx/run
Normal file
35
comicarr/rootfs/etc/services.d/nginx/run
Normal file
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
# ==============================================================================
|
||||
|
||||
# Wait for Comicarr to answer before nginx starts serving ingress. First boot
|
||||
# runs the alembic migrations against a cold 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.
|
||||
# The per probe timeouts keep the 15 minute ceiling real : without them a half
|
||||
# open connection would hang a single probe, and the loop, forever.
|
||||
# A wall clock deadline, not an attempt count : a failed probe costs up to
|
||||
# max-time on top of the sleep, so counting attempts would stretch the wait to
|
||||
# roughly twice the advertised ceiling.
|
||||
comicarr_ready=false
|
||||
deadline=$((SECONDS + 900))
|
||||
while [ "$SECONDS" -lt "$deadline" ]; do
|
||||
if curl -sf --connect-timeout 2 --max-time 5 -o /dev/null "http://127.0.0.1:8090/api/health"; then
|
||||
comicarr_ready=true
|
||||
break
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
|
||||
# Deliberately not fatal : nginx serving a 502 tells the user something is wrong
|
||||
# and starts working by itself once Comicarr finally answers, while refusing to
|
||||
# start would take ingress down for good after ha_entrypoint gives up retrying.
|
||||
if [ "$comicarr_ready" != true ]; then
|
||||
bashio::log.warning "Comicarr did not answer within 15 minutes. Starting NGinx anyway : ingress will return 502 until it does."
|
||||
fi
|
||||
|
||||
bashio::log.info "Starting NGinx..."
|
||||
exec nginx
|
||||
10
comicarr/updater.json
Normal file
10
comicarr/updater.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"github_beta": "false",
|
||||
"github_fulltag": false,
|
||||
"last_update": "2026-08-20",
|
||||
"repository": "alexbelgium/hassio-addons",
|
||||
"slug": "comicarr",
|
||||
"source": "github",
|
||||
"upstream_repo": "frankieramirez/comicarr",
|
||||
"upstream_version": "0.34.0"
|
||||
}
|
||||
Reference in New Issue
Block a user