feat(degoog): new add-on for the Degoog search aggregator (#3116)

Degoog mounts every route, and builds every url, under DEGOOG_BASE_URL.
The add-on sets that to its ingress entry, so ingress works with no url
rewriting beyond the one script tag upstream emits without its base path
(/public/t.js in render.tsx). A bundled nginx fronts both the ingress port
and the direct port 4444 and puts the stripped entry back, so
http://homeassistant:4444/search?q=%s works as a browser search engine.

Structure follows comicarr: the upstream image is plain alpine/bun with no
s6-overlay, so ha_entrypoint runs as pid 1 and supervises the app and
nginx. Data lives in /config (addon_config), the equivalent of upstream's
./data:/app/data volume.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
alexbelgium
2026-10-13 15:19:46 +02:00
parent 274a806cce
commit 2423e1498b
17 changed files with 569 additions and 0 deletions

3
degoog/CHANGELOG.md Normal file
View File

@@ -0,0 +1,3 @@
## 1.1.0 (2026-10-13)
- Initial release, based on upstream degoog-org/degoog 1.1.0 (changelog : https://github.com/degoog-org/degoog/releases)
- Home Assistant ingress support, and direct access on port 4444, through a bundled nginx reverse proxy

119
degoog/Dockerfile Normal file
View File

@@ -0,0 +1,119 @@
#============================#
# ALEXBELGIUM'S DOCKERFILE #
#============================#
# _.------.
# _.-` ('>.-`"""-.
# '.--'` _'` _ .--.)
# -' '-.-';` `
# ' - _.' ``'--.
# '---` .-'""`
# /`
#=== Home Assistant Addon ===#
#################
# 1 Build Image #
#################
ARG BUILD_FROM
ARG BUILD_VERSION
ARG BUILD_UPSTREAM="1.1.0"
FROM ghcr.io/degoog-org/degoog:${BUILD_UPSTREAM}
##################
# 2 Modify Image #
##################
USER root
# No S6_* tuning here : the upstream image is a plain oven/bun alpine image 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 /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"
# 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 ships no s6-overlay, so ha_entrypoint runs as pid 1 : it
# executes /etc/cont-init.d, then supervises /etc/services.d. The upstream
# /entrypoint.sh is still what services.d/degoog/run starts the app with.
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 #
#################
# Goes through nginx on the direct port, which maps / onto the app's base path,
# so one probe covers both processes
ENV HEALTH_PORT="4444" \
HEALTH_URL="/readyz"
HEALTHCHECK \
--interval=30s \
--retries=5 \
--start-period=90s \
--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

68
degoog/README.md Normal file
View File

@@ -0,0 +1,68 @@
# Home Assistant Add-on: Degoog
Self-hosted search aggregator: one query, results from many search engines, with themes and a
plugin store.
[Degoog](https://github.com/degoog-org/degoog) works like SearXNG: it sends your search to the
engines you pick and merges what they return. Engines, plugins, themes and autocomplete
providers are installed from its built-in store.
## About
- Results from many engines at once, merged into one page
- Engines, plugins, themes and transports installed from git-based store repositories
- Bangs, shortcuts, autocomplete and an optional local result indexer
- Works as your browser's default search engine (OpenSearch)
## Installation
1. Add this repository to Home Assistant.
2. Install the **Degoog** add-on.
3. Set `DEGOOG_SETTINGS_PASSWORDS` (see below), then start the add-on.
4. Open it from the sidebar (ingress), or at `http://homeassistant:4444`.
5. Go to **Settings → Store** and install at least one search engine: a fresh install has none,
so searches return no web results until you do.
## Configuration
| Option | Description |
|--------|-------------|
| `DEGOOG_SETTINGS_PASSWORDS` | Password for the settings and admin pages. Several passwords can be given, comma separated. If empty, Degoog generates a new one-off password at every start and prints it in the add-on log. |
| `PUID` / `PGID` | User Degoog runs as, and owner of its data directory. Defaults to `0` (root). |
| `TZ` | Timezone, e.g. `Europe/Paris`. |
| `env_vars` | Extra environment variables passed to Degoog, e.g. `DEGOOG_PUBLIC_INSTANCE` or `DEGOOG_I18N`. See the [upstream list](https://degoog-org.github.io/docs/environment-variables.html) and the [wiki](https://github.com/alexbelgium/hassio-addons/wiki/Add-Environment-variables-to-your-Addon-2). |
The add-on sets `DEGOOG_BASE_URL`, `DEGOOG_DATA_DIR`, `DEGOOG_PORT` and `DEGOOG_BIND_ADDRESS`
itself, because ingress, the direct port and the health check are built around them: setting
them in `env_vars` has no effect.
## Ingress, direct access and search-engine use
Degoog serves every page under a base path. The add-on sets that base path to the Home Assistant
ingress path, so ingress needs no rewriting, and the bundled nginx maps port `4444` onto the same
path. As a result, pages opened on port `4444` show an address such as
`http://homeassistant:4444/api/hassio_ingress/<token>/search?q=...`. That is expected, and the
short form keeps working too.
To use Degoog as your browser's search engine, use the direct port, not the Home Assistant
sidebar url, for example `http://homeassistant:4444/search?q=%s`. Ingress urls only work inside
a logged-in Home Assistant session.
Behind nginx every client appears to Degoog as `127.0.0.1`, so its per-IP rate limits apply to
all users together. Its bot trap never bans private addresses, so this cannot lock you out. If
you put the add-on behind your own reverse proxy and want per-client limits, add
`DEGOOG_DISTRUST_PROXY=0` in `env_vars`. Degoog then trusts the `X-Forwarded-For` header, which
clients can forge, so only do this when port `4444` is reachable only through your proxy.
## Data
Settings, installed extensions and the index database live in `/config` inside the add-on.
Home Assistant maps that to this add-on's own configuration directory,
`/addon_configs/<repository_id>_degoog`, and it is included in add-on backups. It is the
equivalent of the upstream `./data:/app/data` compose volume, so the contents of an existing
`data` folder can be copied in as is.
## Support
- [Degoog upstream project](https://github.com/degoog-org/degoog)
- [Add-on repository issues](https://github.com/alexbelgium/hassio-addons/issues)

66
degoog/apparmor.txt Normal file
View File

@@ -0,0 +1,66 @@
#include <tunables/global>
profile degoog_addon flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
capability chown,
capability dac_override,
capability fowner,
capability setgid,
capability setuid,
capability sys_chroot,
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
degoog/build.json Normal file
View File

@@ -0,0 +1,6 @@
{
"build_from": {
"aarch64": "ghcr.io/degoog-org/degoog:latest",
"amd64": "ghcr.io/degoog-org/degoog:latest"
}
}

32
degoog/config.yaml Normal file
View File

@@ -0,0 +1,32 @@
arch:
- aarch64
- amd64
description:
Search aggregator that queries many engines at once, with themes and a
plugin store
image: ghcr.io/alexbelgium/degoog-{arch}
ingress: true
init: false
map:
- addon_config:rw
name: Degoog
options:
env_vars: []
PGID: 0
PUID: 0
panel_icon: mdi:magnify
ports:
4444/tcp: 4444
ports_description:
4444/tcp: Web interface
schema:
DEGOOG_SETTINGS_PASSWORDS: password?
env_vars:
- name: match(^[A-Za-z0-9_]+$)
value: str?
PGID: int
PUID: int
TZ: str?
slug: degoog
url: https://github.com/alexbelgium/hassio-addons/tree/master/degoog
version: "1.1.0"

BIN
degoog/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
degoog/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1,19 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
# Degoog keeps its settings, plugins, themes, engines and sqlite indexer in its
# data directory. services.d/degoog/run points DEGOOG_DATA_DIR at /config, the
# addon_config mount, which matches the upstream compose file's
# "./data:/app/data" volume : an existing data folder can be copied in as is.
bashio::log.info "Data stored in /config"
# Recursive, like the upstream entrypoint does for /app/data : plugins and
# themes are installed by the app itself, so a PUID change must hand them over
# too. Numbered 20- so it sorts after 00-global_var.sh, which exports PUID/PGID.
chown -R "${PUID:-0}:${PGID:-0}" /config
if [ -n "${TZ:-}" ] && [ -f "/usr/share/zoneinfo/${TZ}" ]; then
ln -sf "/usr/share/zoneinfo/${TZ}" /etc/localtime
echo "${TZ}" > /etc/timezone
fi

View 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

View 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;
}

View File

@@ -0,0 +1 @@
resolver 127.0.0.11 ipv6=off;

View 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;
}

View File

@@ -0,0 +1,50 @@
server {
# Ingress, and the direct port. Both are served the same way : Degoog runs
# with its base path set to the ingress entry (services.d/degoog/run), and
# Home Assistant strips that entry before forwarding, so it is put back here.
listen %%interface%%:%%port%% default_server;
listen 4444 default_server;
client_max_body_size 0;
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;
# Search results are sent to the page as server-sent events
proxy_buffering off;
proxy_read_timeout 30m;
proxy_send_timeout 30m;
# The one url upstream builds without its base path
# (src/server/routes/pages/render.tsx)
proxy_set_header Accept-Encoding "";
sub_filter 'src="/public/t.js' 'src="%%ingress_entry%%/public/t.js';
# Degoog answers <entry>/ with a redirect to the slashless <entry>, which
# Home Assistant does not route : ask for the slashless form directly.
location = / {
proxy_pass http://127.0.0.1:4445%%ingress_entry%%;
}
# Links in the pages already carry the entry ; only the direct port sees
# them, since ingress strips it. No trailing slash, so the bare entry
# (the target of Degoog's own trailing-slash redirect) matches too.
location %%ingress_entry%% {
proxy_pass http://127.0.0.1:4445;
}
# Transport websockets are the only routes upstream mounts outside its base
# path (src/server/index.ts)
location /ws/ {
proxy_pass http://127.0.0.1:4445;
}
location / {
proxy_pass http://127.0.0.1:4445%%ingress_entry%%/;
}
}

View File

@@ -0,0 +1,19 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
# ==============================================================================
# Every route Degoog serves, and every url it generates, lives under
# DEGOOG_BASE_URL. Setting it to the ingress entry makes the pages correct under
# ingress as they are ; nginx maps the direct port onto the same path.
# The port and bind address are forced because nginx and the healthcheck are
# built around them.
DEGOOG_BASE_URL="$(bashio::addon.ingress_entry)"
export DEGOOG_BASE_URL
export DEGOOG_DATA_DIR=/config
export DEGOOG_PORT=4445
export DEGOOG_BIND_ADDRESS=127.0.0.1
bashio::log.info "Starting Degoog..."
cd /app
exec /entrypoint.sh

View File

@@ -0,0 +1,7 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
# ==============================================================================
bashio::log.info "Starting NGinx..."
exec nginx

10
degoog/updater.json Normal file
View File

@@ -0,0 +1,10 @@
{
"github_beta": "false",
"github_fulltag": false,
"last_update": "2026-10-13",
"repository": "alexbelgium/hassio-addons",
"slug": "degoog",
"source": "github",
"upstream_repo": "degoog-org/degoog",
"upstream_version": "1.1.0"
}