diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index fde4f6c..3fb2e10 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -29,29 +29,39 @@ env: jobs: ## Clash - docker_clash: - name: "app-clash" + job-clash: + name: "clash" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: | - source ./tool.sh && build_image app-clash latest docker_clash/clash.Dockerfile && push_image clash + source ./tool.sh && build_image clash latest docker_clash/clash.Dockerfile && push_image clash + + ## Selkies + job-gui-linux: + name: "gui-linux" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - run: | + source ./tool.sh && build_image gui-linux latest docker_gui/gui_linux.Dockerfile && push_image gui + ## Casdoor - docker_casdoor: + job-casdoor: name: "casdoor" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: | source ./tool.sh && build_image casdoor latest docker_casdoor/casdoor.Dockerfile && push_image casdoor ## Keycloak - docker_keycloak: + job-keycloak: name: "keycloak" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: | source ./tool.sh && build_image keycloak latest docker_keycloak/keycloak.Dockerfile && push_image keycloak @@ -60,7 +70,7 @@ jobs: name: "dev-hub" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: | source ./tool.sh build_image dev-hub latest docker_devbox/hub.Dockerfile \ @@ -72,7 +82,7 @@ jobs: name: "dev-hub-traefik" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: | source ./tool.sh build_image dev-hub-traefik latest docker_devbox/hub.Dockerfile \ @@ -86,7 +96,7 @@ jobs: name: "openresty" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: | source ./tool.sh && build_image openresty latest docker_openresty/openresty.Dockerfile && push_image openresty @@ -95,7 +105,7 @@ jobs: name: "searxng" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: | source ./tool.sh && build_image searxng latest docker_searxng/searxng.Dockerfile && push_image searxng @@ -104,7 +114,7 @@ jobs: name: "storebox" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: | source ./tool.sh build_image storebox latest docker_storebox/storebox.Dockerfile && push_image storebox @@ -114,7 +124,7 @@ jobs: name: "logent" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: | source ./tool.sh build_image logent latest docker_logent/logent.Dockerfile && push_image logent @@ -124,7 +134,7 @@ jobs: name: "nocobase" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: | source ./tool.sh build_image nocobase latest docker_nocobase/nocobase.Dockerfile && push_image nocobase @@ -134,7 +144,7 @@ jobs: name: "openclaw" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: | source ./tool.sh build_image openclaw latest docker_openclaw/openclaw.Dockerfile && push_image openclaw @@ -144,7 +154,7 @@ jobs: name: "developer,base-dev" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: | source ./tool.sh && free_diskspace build_image base-dev latest docker_devbox/dev.Dockerfile \ @@ -158,7 +168,7 @@ jobs: name: "data-science-dev" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: | source ./tool.sh && free_diskspace build_image data-science-dev latest docker_devbox/dev.Dockerfile \ @@ -173,7 +183,7 @@ jobs: name: "full-stack-dev" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: | source ./tool.sh && free_diskspace build_image full-stack-dev latest docker_devbox/dev.Dockerfile \ @@ -188,7 +198,7 @@ jobs: name: "full-cuda,cuda-dev" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: | source ./tool.sh && free_diskspace build_image cuda-dev latest docker_devbox/dev.Dockerfile \ @@ -212,13 +222,14 @@ jobs: "job-searxng", "job-openresty", "job-dev-hub", - "docker_keycloak", - "docker_casdoor", - "docker_clash", + "job-keycloak", + "job-casdoor", + "job-clash", + "job-gui-linux" ] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - env: AUTH_FILE_CONTENT: ${{ secrets.AUTH_FILE_CONTENT }} DOCKER_MIRROR_REGISTRY: ${{ vars.DOCKER_MIRROR_REGISTRY }} diff --git a/docker_casdoor/work/script-setup-casdoor.sh b/docker_casdoor/work/script-setup-casdoor.sh index a9557c5..6c2dedc 100644 --- a/docker_casdoor/work/script-setup-casdoor.sh +++ b/docker_casdoor/work/script-setup-casdoor.sh @@ -13,8 +13,8 @@ setup_casdoor() { && mkdir -pv /opt/casdoor/web/build /opt/casdoor/conf echo "--> Building Backend..." \ - && cd /tmp/casdoor && echo "${VER_CASDOOR}" > /tmp/casdoor/version_info.txt \ - && CGO_ENABLED=0 GOOS=linux GOARCH=${ARCH} go build -ldflags="-w -s -X 'github.com/casdoor/casdoor/util.Version=${VER_CASDOOR}'" -o "server_linux_${ARCH}" . \ + && cd /tmp/casdoor && echo "v${VER_CASDOOR}" > /tmp/casdoor/version_info.txt \ + && CGO_ENABLED=0 GOOS=linux GOARCH=${ARCH} go build -ldflags="-w -s -X 'github.com/casdoor/casdoor/util.Version=v${VER_CASDOOR}'" -o "server_linux_${ARCH}" . \ && mv "./server_linux_${ARCH}" ./swagger ./docker-entrypoint.sh ./version_info.txt /opt/casdoor/ \ && cat ./conf/app.conf | sort > /opt/casdoor/conf/app.conf \ && ln -sf "/opt/casdoor/server_linux_${ARCH}" /opt/casdoor/server ; diff --git a/docker_clash/README.md b/docker_clash/README.md index a69ddbf..9f27156 100644 --- a/docker_clash/README.md +++ b/docker_clash/README.md @@ -9,10 +9,10 @@ ```shell docker run -d \ - --name=app-clash \ + --name=svc-clash \ -p 7890:7890 -p 9090:9090 \ - -e PROXY_PROVIDER="https://subs.zeabur.app/clash" \ - labnow/app-clash + -e PROXY_PROVIDER="https://raw.githubusercontent.com/snakem982/proxypool/main/source/clash-meta.yaml" \ + labnow/clash ``` After the container starts, visit this page to manage proxy: http://localhost:9090/ui/ui-zashboard/ diff --git a/docker_clash/clash.Dockerfile b/docker_clash/clash.Dockerfile index 545f8fb..f71ebce 100644 --- a/docker_clash/clash.Dockerfile +++ b/docker_clash/clash.Dockerfile @@ -26,5 +26,5 @@ RUN set -eux \ && echo 'export PATH=${PATH}:/opt/clash' >> /etc/profile.d/path-clash.sh \ && ln -sf /opt/clash/clash /usr/local/bin/ -ENV PROXY_PROVIDER="https://subs.zeabur.app/clash" +ENV PROXY_PROVIDER="https://raw.githubusercontent.com/snakem982/proxypool/main/source/clash-meta.yaml" CMD ["/opt/clash/start-clash.sh"] diff --git a/docker_clash/demo/docker-compose.yml b/docker_clash/demo/docker-compose.yml index 014b7a8..10bd3f9 100644 --- a/docker_clash/demo/docker-compose.yml +++ b/docker_clash/demo/docker-compose.yml @@ -1,6 +1,6 @@ services: svc-clash: - image: docker.io/labnow/app-clash + image: docker.io/labnow/clash container_name: svc-clash hostname: svc-clash restart: unless-stopped diff --git a/docker_gui/README.md b/docker_gui/README.md new file mode 100644 index 0000000..fccc896 --- /dev/null +++ b/docker_gui/README.md @@ -0,0 +1,113 @@ +# GUI Linux + +这个镜像用于打包 Selkies-GStreamer,把容器内的 Linux GUI 会话通过浏览器访问。 +镜像只负责 GUI 串流层,默认关闭 Selkies 内置 Basic Auth,认证和鉴权建议放在上游网关、反向代理或平台侧处理。 + +## 构建 + +```bash +docker build -f docker_gui/gui_linux.Dockerfile -t labnow/gui:selkies docker_gui +``` + +基础镜像假设满足以下条件: + +- 基于 Ubuntu。 +- 已包含 Node.js 最新 LTS。 +- 已包含 Python >= 3.13。 + +构建过程会安装 Selkies 运行期系统依赖,默认克隆 Selkies `main` 分支最新源码,并安装到 `/opt/selkies`。 +默认使用源码构建方式,只保留运行期需要的 Python venv、web dashboard 产物和少量 addon 产物,构建依赖会在同一层内清理。 + +如需固定某个 branch、tag 或 commit,可以使用: + +```bash +docker build -f docker_gui/gui_linux.Dockerfile \ + --build-arg ARG_SELKIES_REF=main \ + -t labnow/gui:selkies docker_gui +``` + +如需回退到官方 portable release 包,可以使用: + +```bash +docker build -f docker_gui/gui_linux.Dockerfile \ + --build-arg ARG_SELKIES_INSTALL_METHOD=release \ + -t labnow/gui:selkies-release docker_gui +``` + +## 启动 + +```bash +docker run --rm -p 8080:8080 labnow/gui:selkies +``` + +浏览器访问: + +```text +http://localhost:8080 +``` + +默认不需要输入用户名和密码。如果确实需要启用 Selkies 内置 Basic Auth,可以显式传入: + +```bash +docker run --rm -p 8080:8080 \ + -e SELKIES_ENABLE_BASIC_AUTH=true \ + -e SELKIES_BASIC_AUTH_USER=user \ + -e SELKIES_BASIC_AUTH_PASSWORD=mypasswd \ + labnow/gui:selkies +``` + +## 常用环境变量 + +| 变量 | 默认值 | 说明 | +| --- | --- | --- | +| `SELKIES_ADDR` | `0.0.0.0` | HTTP/WebSocket 监听地址。 | +| `SELKIES_PORT` | `8080` | HTTP/WebSocket 监听端口。 | +| `SELKIES_ENABLE_BASIC_AUTH` | `false` | 是否启用 Selkies 内置 Basic Auth。 | +| `SELKIES_BASIC_AUTH_USER` | 空 | Basic Auth 用户名。 | +| `SELKIES_BASIC_AUTH_PASSWORD` | 空 | Basic Auth 密码。 | +| `SELKIES_ENCODER` | `x264enc` | 视频编码器。 | +| `SELKIES_ENABLE_RESIZE` | `false` | 是否允许 Selkies 按浏览器窗口调整分辨率。 | +| `SELKIES_STUN_HOST` | `stun.l.google.com` | STUN 服务器地址。 | +| `SELKIES_STUN_PORT` | `19302` | STUN 服务器端口。 | +| `SELKIES_TURN_HOST` | 空 | TURN 服务器地址。Docker bridge、NAT 或代理场景通常需要配置。 | +| `SELKIES_TURN_PORT` | `3478` | TURN 服务器端口。 | +| `SELKIES_TURN_PROTOCOL` | `udp` | TURN 传输协议。 | +| `SELKIES_TURN_TLS` | `false` | TURN 是否启用 TLS。 | +| `SELKIES_TURN_USERNAME` | 空 | TURN 用户名。 | +| `SELKIES_TURN_PASSWORD` | 空 | TURN 密码。 | +| `SELKIES_TURN_SHARED_SECRET` | 空 | TURN shared secret,用于 HMAC 临时凭证。 | + +也可以直接传递 `selkies-gstreamer-run` 参数: + +```bash +docker run --rm -p 8080:8080 labnow/gui:selkies --encoder=vp8enc --enable_resize=true +``` + +## 关于 Connection failed + +`8080` 端口只承载 Web UI 和 signaling WebSocket。Selkies 的画面、音频、输入等媒体流走 WebRTC,WebRTC 会通过 ICE 协商额外的 UDP/TCP candidate。 + +因此,只做 `-p 8080:8080` 时,页面可以打开,但媒体流不一定能连通。如果浏览器提示 `Connection failed`,通常不是 HTTP 端口映射失败,而是 ICE/WebRTC 连接失败。 + +常见处理方式: + +- 本地 Linux 开发时,优先使用 `--network=host`,让浏览器能直接访问容器产生的 ICE candidate。 +- Docker bridge、跨主机、NAT、反向代理、只允许暴露一个 HTTP 端口的部署,建议配置外部 TURN 服务。 +- 如果不使用 TURN,需要额外开放 WebRTC 实际使用的 UDP/TCP 端口范围,并确保浏览器能路由到日志里的 candidate 地址。 + +外部 TURN 示例: + +```bash +docker run --rm -it -p 8080:8080 \ + quay.io/labnow0dev/gui-linux bash + +# optional env: + -e SELKIES_TURN_PROTOCOL=tcp \ + -e SELKIES_TURN_TLS=true \ + -e SELKIES_TURN_HOST=turn.example.com \ + -e SELKIES_TURN_PORT=443 \ + -e SELKIES_TURN_USERNAME="$TURN_USERNAME" \ + -e SELKIES_TURN_PASSWORD="$TURN_PASSWORD" \ +``` + +日志中出现 `Listening on http://0.0.0.0:8080` 表示 HTTP 服务已经启动。若随后反复出现 session 建立、ICE candidate 交换、peer cleanup,通常应优先检查 TURN、网络模式或 UDP/TCP candidate 可达性。 diff --git a/docker_gui/gui_linux.Dockerfile b/docker_gui/gui_linux.Dockerfile new file mode 100644 index 0000000..c8c861f --- /dev/null +++ b/docker_gui/gui_linux.Dockerfile @@ -0,0 +1,69 @@ +# Distributed under the terms of the Modified BSD License. + +ARG BASE_NAMESPACE +ARG BASE_IMG_BUILD="node" +ARG BASE_IMG="base" +ARG ARG_SELKIES_INSTALL_METHOD=source +ARG ARG_SELKIES_REF=main + + +# Stage 1: build selkies from source +FROM ${BASE_NAMESPACE:+$BASE_NAMESPACE/}${BASE_IMG_BUILD} AS builder + +ARG ARG_SELKIES_INSTALL_METHOD=source +ARG ARG_SELKIES_REF=main + +COPY work /opt/utils/ + +RUN set -eux && chmod +x /opt/utils/*.sh \ + && source /opt/utils/script-utils.sh \ + && source /opt/utils/script-setup-gui.sh \ + && install_apt /opt/utils/install_list_selkies.apt \ + && if [ "${ARG_SELKIES_INSTALL_METHOD}" = "release" ] ; then \ + setup_selkies_from_release ; \ + else \ + export VER_SELKIES_REF="${ARG_SELKIES_REF}" ; \ + setup_selkies_build_dependencies && setup_selkies_from_source ; \ + fi \ + && mv /opt/utils/docker-entrypoint.sh /opt/selkies/docker-entrypoint.sh \ + && mv /opt/utils/install_list_selkies.apt /opt/selkies/ \ + && chmod +x /opt/selkies/docker-entrypoint.sh + + +# Stage 2: runtime image +FROM ${BASE_NAMESPACE:+$BASE_NAMESPACE/}${BASE_IMG} + +LABEL maintainer="postmaster@labnow.ai" + +COPY --from=builder /opt/selkies /opt/selkies + +RUN set -eux && cd /opt/selkies \ + && source /opt/utils/script-utils.sh \ + && install_apt /opt/selkies/install_list_selkies.apt \ + && apt install -y build-essential cmake pkg-config libx11-dev libxext-dev libxfixes-dev libjpeg-dev libx264-dev libyuv-dev libavcodec-dev libavutil-dev libva-dev \ + && pip install --no-cache-dir --no-binary :all: pixelflux \ + && apt purge -y build-essential cmake pkg-config libx11-dev libxext-dev libxfixes-dev libjpeg-dev libx264-dev libyuv-dev libavcodec-dev libavutil-dev libva-dev \ + && pip install --no-cache-dir ./*.whl \ + && if [ -f /opt/selkies/lib/selkies_joystick_interposer.so ]; then \ + ln -sf /opt/selkies/lib/selkies_joystick_interposer.so /usr/lib/selkies_joystick_interposer.so ; \ + fi \ + && if [ -f /opt/selkies/lib/libudev.so.1.0.0-fake ]; then \ + ln -sf /opt/selkies/lib/libudev.so.1.0.0-fake /usr/lib/libudev.so.1.0.0-fake \ + && ln -sf /opt/selkies/lib/libudev.so.1.0.0-fake /usr/lib/libudev.so.1 \ + && ln -sf /opt/selkies/lib/libudev.so.1.0.0-fake /usr/lib/libudev.so ; \ + fi \ + && list_installed_packages && install__clean + +ENV PATH=/opt/selkies:/opt/conda/bin:${PATH} + +EXPOSE 8080 +WORKDIR /opt/selkies + +# '-c' option make bash commands are read from string. +# If there are arguments after the string, they are assigned to the positional parameters, starting with $0. +# '-o pipefail' prevents errors in a pipeline from being masked. +# If any command in a pipeline fails, that return code will be used as the return code of the whole pipeline. +# '--login': make bash first reads and executes commands from the file /etc/profile, if that file exists. +# After that, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable. +SHELL ["/bin/bash", "--login", "-o", "pipefail", "-c"] +ENTRYPOINT ["/opt/selkies/docker-entrypoint.sh"] diff --git a/docker_gui/work/docker-entrypoint.sh b/docker_gui/work/docker-entrypoint.sh new file mode 100644 index 0000000..a8cdaff --- /dev/null +++ b/docker_gui/work/docker-entrypoint.sh @@ -0,0 +1,169 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +# +# Runtime env +# +export DISPLAY="${DISPLAY:-:99}" + +export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/tmp/runtime-root}" +export PIPEWIRE_RUNTIME_DIR="${PIPEWIRE_RUNTIME_DIR:-$XDG_RUNTIME_DIR}" + +export PULSE_RUNTIME_PATH="${PULSE_RUNTIME_PATH:-$XDG_RUNTIME_DIR/pulse}" +export PULSE_SERVER="${PULSE_SERVER:-unix:$PULSE_RUNTIME_PATH/native}" + +export SELKIES_ENABLE_BASIC_AUTH="${SELKIES_ENABLE_BASIC_AUTH:-false}" +export SELKIES_ENABLE_RESIZE="${SELKIES_ENABLE_RESIZE:-false}" +export SELKIES_ENABLE_HTTPS="${SELKIES_ENABLE_HTTPS:-false}" + +mkdir -pv "$XDG_RUNTIME_DIR" "$PULSE_RUNTIME_PATH" + +chmod 700 "$XDG_RUNTIME_DIR" + +# +# Xvfb +# +if ! xdpyinfo -display "$DISPLAY" >/dev/null 2>&1; then + Xvfb "$DISPLAY" \ + -screen 0 "${XVFB_SCREEN:-3840x2160x24}" \ + +extension RANDR \ + +extension GLX \ + +extension RENDER \ + -nolisten tcp \ + >/tmp/xvfb.log 2>&1 & +fi + +# +# wait X ready +# +for _ in $(seq 1 50); do + xdpyinfo -display "$DISPLAY" >/dev/null 2>&1 && break + sleep 0.2 +done + +xdpyinfo -display "$DISPLAY" >/dev/null 2>&1 || { + echo "Xvfb failed to start" + cat /tmp/xvfb.log || true + exit 1 +} + +# +# Openbox +# +if command -v openbox >/dev/null 2>&1; then + openbox >/tmp/openbox.log 2>&1 & +fi + +# +# xsettingsd +# +if command -v xsettingsd >/dev/null 2>&1; then + mkdir -p /root/.config/xsettingsd + + cat >/root/.config/xsettingsd/xsettingsd.conf </dev/null 2>&1 || true + xsettingsd >/tmp/xsettingsd.log 2>&1 & +fi + +# +# PulseAudio +# +if command -v pulseaudio >/dev/null 2>&1; then + pulseaudio \ + --system \ + --daemonize=yes \ + --disallow-exit \ + --exit-idle-time=-1 \ + >/tmp/pulseaudio.log 2>&1 || true + + # + # wait pulseaudio ready + # + for _ in $(seq 1 30); do + pactl info >/dev/null 2>&1 && break + sleep 0.2 + done + + # + # create dummy sink if missing + # + if pactl info >/dev/null 2>&1; then + if ! pactl list short sinks | grep -q '^output'; then + pactl load-module module-null-sink \ + sink_name=output \ + sink_properties=device.description=output \ + >/dev/null + fi + fi +fi + +# +# Selkies args +# +args=( + "--addr=${SELKIES_ADDR:-0.0.0.0}" + "--port=${SELKIES_PORT:-8080}" + "--web-root=${SELKIES_WEB_ROOT:-/opt/selkies/share/selkies-web}" + + "--encoder=${SELKIES_ENCODER:-x264enc}" + + "--stun-host=${SELKIES_STUN_HOST:-stun.l.google.com}" + "--stun-port=${SELKIES_STUN_PORT:-19302}" + + "--enable-https=${SELKIES_ENABLE_HTTPS}" + "--enable-basic-auth=${SELKIES_ENABLE_BASIC_AUTH}" + "--enable-resize=${SELKIES_ENABLE_RESIZE}" +) + +# +# HTTPS +# +if [ "$SELKIES_ENABLE_HTTPS" = "true" ]; then + args+=( + "--https-cert=${SELKIES_HTTPS_CERT:-/etc/ssl/certs/ssl-cert-snakeoil.pem}" + "--https-key=${SELKIES_HTTPS_KEY:-/etc/ssl/private/ssl-cert-snakeoil.key}" + ) +fi + +# +# Basic auth +# +if [ "$SELKIES_ENABLE_BASIC_AUTH" = "true" ]; then + args+=( + "--basic-auth-user=${SELKIES_BASIC_AUTH_USER:-admin}" + "--basic-auth-password=${SELKIES_BASIC_AUTH_PASSWORD:-admin}" + ) +fi + +# +# TURN +# +if [ -n "${SELKIES_TURN_HOST:-}" ]; then + args+=( + "--turn-host=${SELKIES_TURN_HOST}" + "--turn-port=${SELKIES_TURN_PORT:-3478}" + "--turn-protocol=${SELKIES_TURN_PROTOCOL:-udp}" + ) + + [ "${SELKIES_TURN_TLS:-false}" = "true" ] && \ + args+=("--turn-tls=true") + + [ -n "${SELKIES_TURN_USERNAME:-}" ] && \ + args+=("--turn-username=${SELKIES_TURN_USERNAME}") + + [ -n "${SELKIES_TURN_PASSWORD:-}" ] && \ + args+=("--turn-password=${SELKIES_TURN_PASSWORD}") + + [ -n "${SELKIES_TURN_SHARED_SECRET:-}" ] && \ + args+=("--turn-shared-secret=${SELKIES_TURN_SHARED_SECRET}") +fi + +set -x +exec /opt/selkies/selkies-gstreamer-run "${args[@]}" diff --git a/docker_gui/work/install_list_selkies.apt b/docker_gui/work/install_list_selkies.apt new file mode 100644 index 0000000..2efcd4a --- /dev/null +++ b/docker_gui/work/install_list_selkies.apt @@ -0,0 +1,40 @@ +% ============================================================================== +% Selkies Docker Image APT Package Dependencies +% ============================================================================== + +% 1. X11 Virtual Display & Core Services +xvfb xserver-xorg-core dbus-x11 % Headless virtual display server, core Xorg framework, and DBus for IPC. +x11-xserver-utils x11-utils x11-xkb-utils % Core X11 utilities for resolution scaling, window management, and key mapping. + +% 2. Desktop Environment & Window Management +openbox xsettingsd xclip % Lightweight window manager, X11 daemon config, and remote clipboard support. + +% 3. Screen Capture & Remote Input Libraries +libx11-xcb1 libxcb-dri3-0 libxext6 % XCB interoperability and DRI3 hardware graphics acceleration. +libxdamage1 libxfixes3 libxv1 % Screen damage tracking and cursor fixes for low-latency capture. +libxtst6 % X Test extension for injecting remote WebRTC mouse and keyboard events. + +% 4. Keyboard Layout & Input Mapping +libxkbcommon0 libxkbcommon-dev % Keyboard layout processing and keycode translation for remote input. + +% 5. Wayland Compatibility Layer +wayland-protocols libwayland-egl1 % Wayland display protocols and EGL hardware-accelerated rendering contexts. + +% 6. Audio Server Infrastructure +pulseaudio libpulse0 % Virtual audio daemon and client library to intercept container audio streams. + +% 7. GStreamer Multimedia Pipeline Core +gstreamer1.0-tools gstreamer1.0-plugins-base gstreamer1.0-gl % GStreamer CLI, base plugins, and OpenGL support for hardware rendering. +gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav % Comprehensive plugins (including FFmpeg/H.264) for video stream encoding. + +% 8. GStreamer Audio Bridging +gstreamer1.0-alsa gstreamer1.0-pulseaudio % Audio I/O plugins routing PulseAudio streams into the WebRTC pipeline. + +% 9. Video Frame Pre-processing +libyuv0 % Essential YUV video scaling and color space conversion before encoding. + +% 10. Control Plane & Language Bindings +python3-gi python3-gst-1.0 % Python bindings for GObject and GStreamer to orchestrate media pipelines. + +% 11. System Level Essentials +libatomic1 % Atomic operations for thread-safe C/C++ audio/video processing. diff --git a/docker_gui/work/script-setup-gui.sh b/docker_gui/work/script-setup-gui.sh new file mode 100644 index 0000000..2be51ad --- /dev/null +++ b/docker_gui/work/script-setup-gui.sh @@ -0,0 +1,137 @@ +# ref: https://selkies-project.github.io/selkies/start/#quick-start +# ref: https://github.com/linuxserver/docker-baseimage-selkies/blob/master/Dockerfile + +source /opt/utils/script-utils.sh + +setup_selkies_build_dependencies() { + apt-get -qq update -yq --fix-missing && apt-get -qq install -yq --no-install-recommends \ + build-essential cmake g++ gcc git libxkbcommon-dev make pkg-config python3-dev python3-venv ; +} + +cleanup_selkies_build_dependencies() { + apt-get purge -y --auto-remove \ + build-essential cmake g++ gcc git libxkbcommon-dev make pkg-config python3-dev \ + python3-venv \ + && rm -rf /tmp/selkies-src /root/.cache /root/.npm /var/tmp/* ; +} + +setup_selkies_from_release() { + [ "$(dpkg --print-architecture)" = "amd64" ] || { + echo "Unsupported architecture for Selkies portable distribution: $(dpkg --print-architecture)" && return 1 ; + } + + VER_SELKIES="$(curl -fsSL "https://api.github.com/repos/selkies-project/selkies/releases/latest" | jq -r '.tag_name' | sed 's/[^0-9.\-]*//g')" \ + && URL_SELKIES="https://github.com/selkies-project/selkies/releases/download/v${VER_SELKIES}/selkies-gstreamer-portable-v${VER_SELKIES}_amd64.tar.gz" \ + && echo "Downloading Selkies-GStreamer ${VER_SELKIES} from: ${URL_SELKIES}" \ + && rm -rf /opt/selkies /tmp/selkies-install \ + && mkdir -pv /tmp/selkies-install \ + && curl -fsSL "${URL_SELKIES}" | tar -xzf - -C /tmp/selkies-install \ + && mv /tmp/selkies-install/selkies-gstreamer /opt/selkies \ + && chmod +x /opt/selkies/selkies-gstreamer* \ + && ln -sf /opt/selkies/selkies-gstreamer-run /usr/local/bin/selkies-gstreamer-run \ + && echo "${VER_SELKIES}" > /opt/selkies/version_info.txt \ + && rm -rf /tmp/selkies-install /opt/selkies/docs ; + + [ -x /opt/selkies/selkies-gstreamer-run ] && echo "@ Version of Selkies-GStreamer $(cat /opt/selkies/version_info.txt)" || return 1 ; +} + +setup_selkies_web_from_source() { + local src_dir="${1:-/tmp/selkies-src}" + local web_dir="${2:-/opt/selkies/share/selkies-web}" + + echo "--> Building Selkies web dashboard..." \ + && cd "${src_dir}/addons/selkies-web-core" \ + && npm install \ + && npm run build \ + && cd "${src_dir}/addons/selkies-dashboard" \ + && cp ../selkies-web-core/dist/selkies-core.js src/ \ + && npm install \ + && npm run build \ + && mkdir -pv "${web_dir}/src" "${web_dir}/nginx" \ + && cp -arf dist/* "${web_dir}/" \ + && cp -f ../selkies-web-core/dist/selkies-core.js "${web_dir}/src/" \ + && cp -f ../universal-touch-gamepad/universalTouchGamepad.js "${web_dir}/src/" \ + && cp -arf ../selkies-web-core/dist/jsdb "${web_dir}/" \ + && cp -arf ../selkies-web-core/nginx/* "${web_dir}/nginx/" \ + && rm -rf "${src_dir}"/addons/*/node_modules /root/.npm /tmp/npm-* ; +} + +setup_selkies_python_from_source() { + local src_dir="${1:-/tmp/selkies-src}" + local dist_dir="/tmp/selkies-dist" + + echo "--> Building Selkies Python package..." \ + && mkdir -p "${dist_dir}" \ + && cd "${src_dir}" \ + && pip install --no-cache-dir --upgrade pip setuptools wheel build \ + && python3 -m build --outdir "${dist_dir}" \ + && cp -r "${dist_dir}"/*.whl /opt/selkies/ \ + && echo "--> Installing Selkies Python package..." \ + && pip install --no-cache-dir "${dist_dir}"/*.whl \ + && rm -rf "${dist_dir}" ; +} + +setup_selkies_addons_from_source() { + local src_dir="${1:-/tmp/selkies-src}" + local lib_dir="/opt/selkies/lib" + + mkdir -p "${lib_dir}" + + if [ -f "${src_dir}/addons/js-interposer/joystick_interposer.c" ]; then + echo "--> Building Selkies joystick interposer..." \ + && gcc -shared -fPIC -ldl -o "${lib_dir}/selkies_joystick_interposer.so" \ + "${src_dir}/addons/js-interposer/joystick_interposer.c" ; + fi + + if [ -f "${src_dir}/addons/fake-udev/Makefile" ]; then + echo "--> Building Selkies fake udev..." \ + && make -C "${src_dir}/addons/fake-udev" \ + && mv "${src_dir}/addons/fake-udev/libudev.so.1.0.0-fake" "${lib_dir}/" ; + fi +} + +setup_selkies_runtime_wrapper() { + cat > /opt/selkies/selkies-gstreamer-run <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +if command -v selkies-gstreamer &>/dev/null; then + exec selkies-gstreamer "$@" +fi +exec selkies "$@" +EOF + chmod +x /opt/selkies/selkies-gstreamer-run \ + && ln -sf /opt/selkies/selkies-gstreamer-run /usr/local/bin/selkies-gstreamer-run ; +} + +checkout_selkies_source() { + local ref="${1:-main}" + local src_dir="${2:-/tmp/selkies-src}" + local repo="https://github.com/selkies-project/selkies.git" + + if git ls-remote --exit-code --heads --tags "${repo}" "${ref}" >/dev/null 2>&1; then + git clone --depth 1 --branch "${ref}" "${repo}" "${src_dir}" ; + else + git clone --filter=blob:none --no-checkout "${repo}" "${src_dir}" \ + && git -C "${src_dir}" fetch --depth 1 origin "${ref}" \ + && git -C "${src_dir}" checkout FETCH_HEAD ; + fi +} + +setup_selkies_from_source() { + # ref: https://github.com/linuxserver/docker-baseimage-selkies/blob/master/Dockerfile + local ref="${VER_SELKIES_REF:-${VER_SELKIES:-main}}" + local src_dir="/tmp/selkies-src" + + echo "Cloning Selkies source at ${ref}" \ + && rm -rf /opt/selkies "${src_dir}" \ + && mkdir -pv /opt/selkies/share \ + && checkout_selkies_source "${ref}" "${src_dir}" \ + && setup_selkies_web_from_source "${src_dir}" /opt/selkies/share/selkies-web \ + && setup_selkies_python_from_source "${src_dir}" \ + && setup_selkies_addons_from_source "${src_dir}" \ + && setup_selkies_runtime_wrapper \ + && git -C "${src_dir}" rev-parse HEAD > /opt/selkies/version_info.txt \ + && rm -rf /tmp/selkies-src /root/.cache /root/.npm /var/tmp/* ; + + [ -x /opt/selkies/selkies-gstreamer-run ] && echo "@ Version of Selkies-GStreamer $(cat /opt/selkies/version_info.txt)" || return 1 ; +} diff --git a/docker_searxng/demo/docker-compose.searxng-with-proxy.yml b/docker_searxng/demo/docker-compose.searxng-with-proxy.yml index ef04347..03814ea 100644 --- a/docker_searxng/demo/docker-compose.searxng-with-proxy.yml +++ b/docker_searxng/demo/docker-compose.searxng-with-proxy.yml @@ -33,7 +33,7 @@ services: max-file: "1" svc-clash: - image: docker.io/labnow/app-clash + image: docker.io/labnow/clash container_name: svc-clash hostname: svc-clash restart: unless-stopped diff --git a/docker_searxng/demo/searxng/settings.yml b/docker_searxng/demo/searxng/settings.yml index 3c42c58..f5033a8 100644 --- a/docker_searxng/demo/searxng/settings.yml +++ b/docker_searxng/demo/searxng/settings.yml @@ -34,5 +34,5 @@ engines: outgoing: proxies: all://: - # need to make sure the containers of app-clash and searxng can communicate with each other - - http://app-clash:7890 + # need to make sure the containers of svc-clash and searxng can communicate with each other + - http://svc-clash:7890