hits / Dockerfile
Sugamdeol's picture
Upload 31 files
44b5a51 verified
Raw
History Blame Contribute Delete
5.58 kB
# =============================================================================
# 9Hits Viewer v6 + FeelingSurf Viewer + /health endpoint - ready for Render.com
#
# Based on the official 9Hits image: https://hub.docker.com/r/9hitste/appv6
# (it carries the correct system libraries plus the viewer tarball baked in).
#
# Why this image exists:
# * The upstream image extracts its 145 MB bzip2 viewer tarball on EVERY
# container start and runs the viewer via an opaque /nh.sh. On free-tier
# CPUs (Render 0.1 vCPU) that runtime extraction stalls for minutes and a
# wedged viewer produces no output and never exits ("Extracting
# 9hitsv6-linux64 ..." then silence forever). We instead extract the
# viewer at BUILD time into /opt/9hits and drive it directly, mirroring
# the official install.sh flow:
# Xvfb :99 -> nhviewer <flags> --exit-on-init (apply config)
# -> nhviewer --auto-start --in-loop --render-to-terminal
# * The v6 viewer requires a TTY (Render doesn't allocate one), so the
# entrypoint runs it under a pseudo-TTY (run_pty.py, with a wedge
# watchdog and output heartbeat).
# * Render web services must listen on 0.0.0.0:$PORT and pass an HTTP
# health check, so the entrypoint also runs a tiny /health HTTP server
# (health_server.py) - perfect target for an uptime ping bot.
# =============================================================================
FROM 9hitste/appv6
ARG FSVIEWER_VERSION=2.5.2
# Add the official FeelingSurf application to the 9Hits image. Both upstream
# viewers are Debian/Ubuntu applications, so they can safely share this image
# and its Chromium/X11 libraries. Pinning the release keeps builds repeatable.
#
# Also extract the 9Hits v6 viewer (baked into the base image at
# /etc/9hitsv6-linux64.tar.bz2) into /opt/9hits NOW, at build time, so the
# container starts instantly instead of decompressing 145 MB of bzip2 on a
# throttled CPU at every boot. The tarball is then removed (whiteout) to save
# runtime disk.
RUN set -eux; \
command -v apt-get >/dev/null 2>&1 || { \
echo "ERROR: the 9Hits base image must provide apt-get" >&2; exit 1; \
}; \
test -f /etc/9hitsv6-linux64.tar.bz2 || { \
echo "ERROR: /etc/9hitsv6-linux64.tar.bz2 missing - base image layout changed?" >&2; exit 1; \
}; \
apt-get update; \
apt-get install -y --no-install-recommends \
python3 ca-certificates wget bzip2 util-linux psmisc bc \
libasound2 libgbm1 libgtk-3-0 libnotify4 libnss3 libsecret-1-0 \
libxss1 libxtst6 libatspi2.0-0 libatomic1 libcanberra-gtk-module \
xdg-utils xvfb x11-utils x11vnc; \
getent group audio >/dev/null || groupadd -r audio; \
getent group fsviewer >/dev/null || groupadd -r fsviewer; \
id fsviewer >/dev/null 2>&1 || useradd -r -m -g fsviewer -G audio fsviewer; \
echo 'pcm.!default {\n type plug\n slave.pcm "null"\n}' > /etc/asound.conf; \
arch="$(dpkg --print-architecture)"; \
wget -q -O /tmp/feelingsurf.deb \
"https://github.com/feelingsurf/viewer/releases/download/${FSVIEWER_VERSION}/FeelingSurfViewer-linux-${arch}-${FSVIEWER_VERSION}.deb"; \
dpkg -i /tmp/feelingsurf.deb || apt-get install -f -y --no-install-recommends; \
test -x /usr/bin/FeelingSurfViewer; \
rm -f /tmp/feelingsurf.deb; \
# --- 9Hits viewer: extract at build time, mirroring official install.sh ---
mkdir -p /opt/9hits /tmp/nhextract; \
tar -xjf /etc/9hitsv6-linux64.tar.bz2 -C /tmp/nhextract; \
if [ -f /tmp/nhextract/nhviewer ]; then \
cp -a /tmp/nhextract/. /opt/9hits/; \
else \
sub="$(find /tmp/nhextract -mindepth 1 -maxdepth 1 -type d | head -n 1)"; \
test -n "$sub" && test -f "$sub/nhviewer" || { \
echo "ERROR: nhviewer not found in the baked tarball" >&2; exit 1; \
}; \
cp -a "$sub"/. /opt/9hits/; \
fi; \
rm -rf /tmp/nhextract; \
chmod -R a+rwX /opt/9hits; \
chmod +x /opt/9hits/nhviewer; \
test -x /opt/9hits/nhviewer; \
rm -f /etc/9hitsv6-linux64.tar.bz2; \
rm -rf /var/lib/apt/lists/* /usr/share/doc/* /usr/share/man/* /tmp/* /var/tmp/*
WORKDIR /
COPY start.sh /start.sh
COPY run_pty.py /run_pty.py
COPY health_server.py /health_server.py
COPY memguard.py /memguard.py
COPY fetch_proxy_list.py /fetch_proxy_list.py
COPY feelingsurf-run.sh /feelingsurf-run.sh
RUN chmod +x /start.sh /run_pty.py /health_server.py /memguard.py /fetch_proxy_list.py /feelingsurf-run.sh
# 512MB dual-viewer survival (see start.sh): LOW_MEMORY shrinks both
# Chromiums, memguard.py restarts the heaviest viewer before the platform can
# OOM the container, and auto mode alternates the viewers when they still
# don't fit simultaneously (Render free = 512 MB).
ENV PORT=10000 \
FEELINGSURF_PORT=3000 \
FEELINGSURF_ENABLED=yes \
SUPERVISOR_DELAY=10 \
NH_DIR=/opt/9hits \
NH_DISPLAY=:99 \
INIT_TIMEOUT=300 \
NH_WATCHDOG=yes \
NH_WATCHDOG_STUCK=600 \
DUAL_VIEWER_MODE=auto \
TIME_SLICE=1500 \
LOW_MEMORY=auto
EXPOSE 10000 3000 5901
HEALTHCHECK --interval=30s --timeout=5s --start-period=45s --retries=3 \
CMD wget -q --spider "http://localhost:${PORT}/health" || exit 1
# /start.sh launches BOTH viewers (supervised + auto-restarted) plus the
# Xvfb display for 9Hits, the combined /health HTTP server, and memguard.py
# (memory guardian / time-slice scheduler for 512 MB plans).
# Extra docker/start-command arguments are forwarded to the nhviewer init pass.
ENTRYPOINT ["/start.sh"]
CMD []