mirror of
https://github.com/Quad4-Software/MeshChatX.git
synced 2026-08-18 09:49:09 -04:00
feat: improve Docker support with new image variants, streamline build scripts, and update documentation for clarity
This commit is contained in:
parent
b960db2e8b
commit
be4fc384af
20 changed files with 207 additions and 143 deletions
15
.github/workflows/docker.yml
vendored
15
.github/workflows/docker.yml
vendored
|
|
@ -60,9 +60,21 @@ jobs:
|
|||
- variant: standard
|
||||
dockerfile: ./Dockerfile
|
||||
tag_suffix: ""
|
||||
build_variant: standard
|
||||
oci_description: "MeshChatX is an all-in-one Reticulum client."
|
||||
oci_licenses: "MIT AND 0BSD"
|
||||
- variant: hardened
|
||||
dockerfile: ./Dockerfile.hardened
|
||||
tag_suffix: "-hardened"
|
||||
build_variant: standard
|
||||
oci_description: "MeshChatX is an all-in-one Reticulum client."
|
||||
oci_licenses: "MIT AND 0BSD"
|
||||
- variant: extra
|
||||
dockerfile: ./Dockerfile
|
||||
tag_suffix: "-extra"
|
||||
build_variant: extra
|
||||
oci_description: "MeshChatX all-in-one Reticulum client with i2pd and yggdrasil."
|
||||
oci_licenses: "MIT AND 0BSD AND BSD-3-Clause AND LGPL-3.0-only"
|
||||
steps:
|
||||
- name: Verify action pins (GitHub API)
|
||||
env:
|
||||
|
|
@ -218,6 +230,9 @@ jobs:
|
|||
OCI_REVISION=${{ github.sha }}
|
||||
OCI_VERSION=${{ steps.oci.outputs.version }}
|
||||
OCI_CREATED=${{ steps.oci.outputs.created }}
|
||||
VARIANT=${{ matrix.build_variant }}
|
||||
OCI_DESCRIPTION=${{ matrix.oci_description }}
|
||||
OCI_LICENSES=${{ matrix.oci_licenses }}
|
||||
|
||||
- name: Verify image has no package bloat
|
||||
run: |
|
||||
|
|
|
|||
6
.github/workflows/security.yml
vendored
6
.github/workflows/security.yml
vendored
|
|
@ -72,7 +72,11 @@ jobs:
|
|||
run: sh scripts/ci/trivy-fs-scan.sh
|
||||
|
||||
- name: Trivy Dockerfile misconfiguration
|
||||
run: trivy config --exit-code 1 Dockerfile
|
||||
run: |
|
||||
set -euo pipefail
|
||||
for f in Dockerfile Dockerfile.hardened; do
|
||||
trivy config --exit-code 1 "$f"
|
||||
done
|
||||
|
||||
frontend:
|
||||
name: Build frontend artifact (CodeQL)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ All notable changes to this project will be documented in this file.
|
|||
- LXST telephony half-duplex mode, live duplex switching, push-to-talk (packetizer squelch), and richer in-call stats (rates plus mute state on the active call)
|
||||
- Optional Linux seccomp-BPF syscall denylist (libseccomp) alongside Landlock, with auto-detect and MESHCHAT_SECCOMP fallback
|
||||
- Bundled [RNS-over-HTTP](https://github.com/Quad4-Software/RNS-over-HTTP) HTTPInterface with Interfaces page client/server setup, auto-install into the Reticulum interface path, and httpx support (Android includes httpx with HTTP/2 as pure-Python wheels)
|
||||
- Docker **extra** image variant (`-extra` suffix): same Alpine Dockerfile with `VARIANT=extra` (adds **i2pd** and **yggdrasil**), built and published beside standard and hardened
|
||||
- Docker Alpine/hardened recipes moved into `scripts/docker/*.sh` so Dockerfiles stay thin (shared frontend, venv, overlay, and runtime setup)
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
|
|||
99
Dockerfile
99
Dockerfile
|
|
@ -1,22 +1,18 @@
|
|||
# Docker Build Stages:
|
||||
# 1. build-frontend: Build static frontend assets using Node
|
||||
# 2. builder: Install third-party deps into /opt/venv-deps, then app overlay
|
||||
# 3. final image: runtime pkgs, deps layer, thin app overlay (better update pulls)
|
||||
#
|
||||
# LXST wheels ship glibc-tagged filterlib extensions only. On Alpine/musl, cffi
|
||||
# compiles at build time; scripts/docker-bake-lxst-filterlib-musl.py copies the
|
||||
# artifact to the import name LXST.filterlib so runtime does not need gcc.
|
||||
# Alpine MeshChatX image.
|
||||
# Stages: frontend, python builder (deps + app overlay), runtime.
|
||||
# VARIANT=standard|extra (extra adds i2pd and yggdrasil).
|
||||
# LXST musl filterlib bake runs in scripts/docker/prepare-venv.sh.
|
||||
|
||||
# ---- Global Build Args ----
|
||||
ARG NODE_IMAGE=node:24-alpine
|
||||
ARG NODE_HASH=sha256:0340fa682d72068edf603c305bfbc10e23219fb0e40df58d9ea4d6f33a9798bf
|
||||
ARG PYTHON_IMAGE=python:3.14.4-alpine3.23
|
||||
ARG PYTHON_HASH=sha256:dd4d2bd5b53d9b25a51da13addf2be586beebd5387e289e798e4083d94ca837a
|
||||
ARG VARIANT=standard
|
||||
ARG OCI_DESCRIPTION="MeshChatX is an all-in-one Reticulum client."
|
||||
ARG OCI_LICENSES="MIT AND 0BSD"
|
||||
|
||||
# ---- STAGE 1: Frontend Build ----
|
||||
FROM --platform=linux/amd64 ${NODE_IMAGE}@${NODE_HASH} AS build-frontend
|
||||
WORKDIR /src
|
||||
# go is required to compile visualiser-wasm
|
||||
RUN apk add --no-cache git python3 go
|
||||
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml vite.config.js ./
|
||||
COPY patches ./patches
|
||||
|
|
@ -27,40 +23,23 @@ COPY scripts/build-visualiser-wasm.mjs scripts/build-visualiser-wasm.mjs
|
|||
COPY scripts/sync-meshchatx-docs.js scripts/sync-meshchatx-docs.js
|
||||
COPY scripts/pip_rns_remotes.py scripts/pip_rns_remotes.py
|
||||
COPY scripts/build/fetch_reticulum_manual.py scripts/build/fetch_reticulum_manual.py
|
||||
COPY scripts/docker/build-frontend.sh scripts/docker/build-frontend.sh
|
||||
COPY docs ./docs
|
||||
COPY visualiser-wasm ./visualiser-wasm
|
||||
COPY meshchatx/src/frontend ./meshchatx/src/frontend
|
||||
ENV GOCACHE=/tmp/go-cache
|
||||
ENV GOTMPDIR=/tmp/go-tmp
|
||||
RUN mkdir -p /tmp/go-cache /tmp/go-tmp && \
|
||||
npm install -g pnpm@11.1.2 && \
|
||||
pnpm config set verify-store-integrity true && \
|
||||
pnpm install --frozen-lockfile && \
|
||||
MESHCHATX_REQUIRE_VISUALISER_WASM=1 pnpm run build-frontend && \
|
||||
test -s meshchatx/src/frontend/public/vendor/visualiser-wasm/visualiser.wasm && \
|
||||
test -s meshchatx/src/frontend/public/vendor/visualiser-wasm/wasm_exec.js && \
|
||||
test -s meshchatx/src/frontend/public/vendor/micron-parser-go/micron-parser-go.wasm && \
|
||||
test -s meshchatx/src/frontend/public/vendor/micron-parser-go/wasm_exec.js && \
|
||||
pnpm run build-docs
|
||||
|
||||
# ---- STAGE 2: Python Builder ----
|
||||
RUN sh scripts/docker/build-frontend.sh
|
||||
|
||||
FROM ${PYTHON_IMAGE}@${PYTHON_HASH} AS builder
|
||||
WORKDIR /build
|
||||
RUN apk upgrade --no-cache && \
|
||||
apk add --no-cache gcc g++ musl-dev linux-headers python3-dev libffi-dev openssl-dev git
|
||||
|
||||
# Install build tools in the system python
|
||||
COPY scripts/docker/builder-apk-alpine.sh scripts/docker/builder-apk-alpine.sh
|
||||
RUN sh scripts/docker/builder-apk-alpine.sh
|
||||
RUN pip install --no-cache-dir --upgrade "pip>=26.0" uv setuptools wheel "jaraco.context>=6.1.0"
|
||||
|
||||
# Create the clean venv for our application dependencies
|
||||
RUN python -m venv /opt/venv
|
||||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
ENV UV_PROJECT_ENVIRONMENT=/opt/venv
|
||||
|
||||
# Install essential runtime tools in the venv (cffi verify needs setuptools on Python 3.12+)
|
||||
RUN pip install --no-cache-dir --upgrade "pip>=26.0" "setuptools" "jaraco.context>=6.1.0"
|
||||
|
||||
COPY pyproject.toml uv.lock README.md CHANGELOG.md ./
|
||||
COPY logo ./logo
|
||||
COPY vendor ./vendor
|
||||
|
|
@ -68,62 +47,31 @@ COPY scripts/docker-bake-lxst-filterlib-musl.py ./scripts/docker-bake-lxst-filte
|
|||
COPY scripts/patch_lxst_pyogg_ogg_ctypes.py ./scripts/patch_lxst_pyogg_ogg_ctypes.py
|
||||
COPY scripts/patch_lxst_codec2_optional.py ./scripts/patch_lxst_codec2_optional.py
|
||||
COPY meshchatx/src/backend/lxst_pyogg_ctypes_compat.py ./meshchatx/src/backend/lxst_pyogg_ctypes_compat.py
|
||||
# Third-party deps layer: stable across app-only updates when uv.lock is unchanged.
|
||||
# --inexact keeps setuptools/jaraco.context already in the venv (cffi bake needs them).
|
||||
RUN uv sync --no-group dev --no-install-project --inexact && \
|
||||
rm -rf /root/.cache/pip /root/.cache/uv && \
|
||||
pip install --no-cache-dir --upgrade "setuptools" "jaraco.context>=6.1.0" && \
|
||||
python scripts/patch_lxst_pyogg_ogg_ctypes.py && \
|
||||
python scripts/patch_lxst_codec2_optional.py && \
|
||||
python scripts/docker-bake-lxst-filterlib-musl.py && \
|
||||
rm -rf /opt/venv/lib/python*/site-packages/LXST/Platforms/android && \
|
||||
find /opt/venv -type d \( -name tests -o -name test -o -name __pycache__ \) -prune -exec rm -rf {} + && \
|
||||
python -m compileall -q /opt/venv/lib/python3.14/site-packages && \
|
||||
cp -a /opt/venv /opt/venv-deps
|
||||
|
||||
COPY scripts/docker/prepare-venv.sh scripts/docker/prepare-venv.sh
|
||||
COPY scripts/docker/build-app-overlay.sh scripts/docker/build-app-overlay.sh
|
||||
RUN sh scripts/docker/prepare-venv.sh
|
||||
COPY meshchatx ./meshchatx
|
||||
COPY --from=build-frontend /src/meshchatx/public ./meshchatx/public
|
||||
RUN sh scripts/docker/build-app-overlay.sh
|
||||
|
||||
# App overlay: meshchatx + vendored packages + console scripts (changes often).
|
||||
RUN pip install --no-cache-dir . && \
|
||||
PYVER="$(python -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')" && \
|
||||
SP="/opt/venv/lib/python${PYVER}/site-packages" && \
|
||||
OUT="/opt/app-overlay" && \
|
||||
mkdir -p "${OUT}/lib/python${PYVER}/site-packages" "${OUT}/bin" && \
|
||||
for pkg in meshchatx lxmfy rns_filesync; do \
|
||||
cp -a "${SP}/${pkg}" "${OUT}/lib/python${PYVER}/site-packages/"; \
|
||||
done && \
|
||||
cp -a "${SP}"/reticulum_meshchatx*.dist-info "${OUT}/lib/python${PYVER}/site-packages/" && \
|
||||
for cmd in meshchat meshchatx meshchatx-repository-http lxmfy rns-filesync; do \
|
||||
cp -a "/opt/venv/bin/${cmd}" "${OUT}/bin/"; \
|
||||
done && \
|
||||
find "${OUT}" -type d -name __pycache__ -prune -exec rm -rf {} + && \
|
||||
python -m compileall -q "${OUT}/lib/python${PYVER}/site-packages"
|
||||
|
||||
# ---- STAGE 3: Final Image ----
|
||||
# Layer order matters for update pulls: base runtime, third-party venv, thin app overlay.
|
||||
FROM ${PYTHON_IMAGE}@${PYTHON_HASH}
|
||||
|
||||
RUN apk upgrade --no-cache && \
|
||||
apk add --no-cache opusfile libffi espeak-ng su-exec && \
|
||||
python -m pip install --no-cache-dir --upgrade "pip>=26.0" "setuptools" "jaraco.context>=6.1.0" && \
|
||||
rm -rf /root/.cache/pip && \
|
||||
addgroup -g 1000 meshchat && adduser -u 1000 -G meshchat -S meshchat && \
|
||||
mkdir -p /config && chown meshchat:meshchat /config
|
||||
|
||||
ARG VARIANT
|
||||
ARG OCI_DESCRIPTION
|
||||
ARG OCI_LICENSES
|
||||
COPY scripts/docker/runtime-setup.sh /tmp/runtime-setup.sh
|
||||
RUN sh /tmp/runtime-setup.sh "${VARIANT}" && rm /tmp/runtime-setup.sh
|
||||
COPY --from=builder --chown=meshchat:meshchat /opt/venv-deps /opt/venv
|
||||
COPY --from=builder --chown=meshchat:meshchat /opt/app-overlay/ /opt/venv/
|
||||
COPY scripts/docker-entrypoint.sh /docker-entrypoint.sh
|
||||
RUN chmod +x /docker-entrypoint.sh
|
||||
|
||||
# Declare after COPY so per-build OCI values do not invalidate runtime or venv layers.
|
||||
ARG OCI_REVISION=""
|
||||
ARG OCI_VERSION=""
|
||||
ARG OCI_CREATED=""
|
||||
|
||||
LABEL org.opencontainers.image.source="https://github.com/Quad4-Software/MeshChatX"
|
||||
LABEL org.opencontainers.image.description="MeshChatX is a all in one Reticulum client."
|
||||
LABEL org.opencontainers.image.licenses="MIT AND 0BSD"
|
||||
LABEL org.opencontainers.image.description="${OCI_DESCRIPTION}"
|
||||
LABEL org.opencontainers.image.licenses="${OCI_LICENSES}"
|
||||
LABEL org.opencontainers.image.authors="Quad4"
|
||||
LABEL org.opencontainers.image.revision="${OCI_REVISION}"
|
||||
LABEL org.opencontainers.image.version="${OCI_VERSION}"
|
||||
|
|
@ -132,12 +80,11 @@ LABEL org.opencontainers.image.created="${OCI_CREATED}"
|
|||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
# No PulseAudio in the image: LXST LineSource/LineSink cannot open host devices.
|
||||
ENV MESHCHAT_FORCE_WEB_AUDIO=1
|
||||
|
||||
USER meshchat
|
||||
|
||||
# Note: Podman defaults to OCI image layout, which drops HEALTHCHECK; use: podman build --format docker
|
||||
# Podman OCI layout drops HEALTHCHECK. Use: podman build --format docker
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=90s --retries=3 \
|
||||
CMD ["python", "-c", "import ssl, urllib.request; urllib.request.urlopen('https://127.0.0.1:8000/api/v1/status', context=ssl._create_unverified_context())"]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
# Multi-stage image on Wolfi (Chainguard): Node dev for frontend, Python dev for
|
||||
# Poetry/cffi builds, Python dev for runtime so native libs can be installed with
|
||||
# apk (the minimal chainguard/python image has no shell or package manager).
|
||||
# Wolfi provides the opus package (libopus); Alpine's opusfile split is not present.
|
||||
# Glibc runtime uses LXST wheels as published; the musl filterlib bake is not used.
|
||||
# Voicemail greeting synthesis is optional without espeak-ng (see voicemail_manager).
|
||||
# Chainguard/Wolfi MeshChatX image (hardened tags).
|
||||
# Glibc LXST wheels as published. Musl filterlib bake is skipped.
|
||||
# Runtime uses opus (not Alpine opusfile). Voicemail without espeak-ng is optional.
|
||||
|
||||
ARG NODE_IMAGE=cgr.dev/chainguard/node:latest-dev
|
||||
ARG PYTHON_BUILD_IMAGE=cgr.dev/chainguard/python:latest-dev
|
||||
|
|
@ -13,7 +10,6 @@ ARG PYTHON_RUNTIME_IMAGE=cgr.dev/chainguard/python:latest-dev
|
|||
FROM --platform=linux/amd64 ${NODE_IMAGE} AS build-frontend
|
||||
USER root
|
||||
WORKDIR /src
|
||||
# go is required to compile visualiser-wasm (gitignored binary; not in image context)
|
||||
RUN apk add --no-cache git python3 go
|
||||
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml vite.config.js ./
|
||||
COPY patches ./patches
|
||||
|
|
@ -24,94 +20,52 @@ COPY scripts/build-visualiser-wasm.mjs scripts/build-visualiser-wasm.mjs
|
|||
COPY scripts/sync-meshchatx-docs.js scripts/sync-meshchatx-docs.js
|
||||
COPY scripts/pip_rns_remotes.py scripts/pip_rns_remotes.py
|
||||
COPY scripts/build/fetch_reticulum_manual.py scripts/build/fetch_reticulum_manual.py
|
||||
COPY scripts/docker/build-frontend.sh scripts/docker/build-frontend.sh
|
||||
COPY docs ./docs
|
||||
COPY visualiser-wasm ./visualiser-wasm
|
||||
COPY meshchatx/src/frontend ./meshchatx/src/frontend
|
||||
ENV GOCACHE=/tmp/go-cache
|
||||
ENV GOTMPDIR=/tmp/go-tmp
|
||||
RUN mkdir -p /tmp/go-cache /tmp/go-tmp && \
|
||||
npm install -g pnpm@11.1.2 && \
|
||||
pnpm config set verify-store-integrity true && \
|
||||
pnpm install --frozen-lockfile && \
|
||||
MESHCHATX_REQUIRE_VISUALISER_WASM=1 pnpm run build-frontend && \
|
||||
test -s meshchatx/src/frontend/public/vendor/visualiser-wasm/visualiser.wasm && \
|
||||
test -s meshchatx/src/frontend/public/vendor/visualiser-wasm/wasm_exec.js && \
|
||||
test -s meshchatx/src/frontend/public/vendor/micron-parser-go/micron-parser-go.wasm && \
|
||||
test -s meshchatx/src/frontend/public/vendor/micron-parser-go/wasm_exec.js && \
|
||||
pnpm run build-docs
|
||||
RUN sh scripts/docker/build-frontend.sh
|
||||
|
||||
FROM ${PYTHON_BUILD_IMAGE} AS builder
|
||||
USER root
|
||||
WORKDIR /build
|
||||
RUN apk add --no-cache build-base git pkgconf openssl-dev libffi-dev linux-headers
|
||||
|
||||
COPY scripts/docker/builder-apk-chainguard.sh scripts/docker/builder-apk-chainguard.sh
|
||||
RUN sh scripts/docker/builder-apk-chainguard.sh
|
||||
RUN pip install --no-cache-dir --upgrade "pip>=26.0" uv setuptools wheel "jaraco.context>=6.1.0"
|
||||
|
||||
RUN python -m venv /opt/venv
|
||||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
ENV UV_PROJECT_ENVIRONMENT=/opt/venv
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade "pip>=26.0" "setuptools" "jaraco.context>=6.1.0"
|
||||
|
||||
COPY pyproject.toml uv.lock README.md CHANGELOG.md ./
|
||||
COPY logo ./logo
|
||||
COPY vendor ./vendor
|
||||
COPY scripts/patch_lxst_pyogg_ogg_ctypes.py ./scripts/patch_lxst_pyogg_ogg_ctypes.py
|
||||
COPY scripts/patch_lxst_codec2_optional.py ./scripts/patch_lxst_codec2_optional.py
|
||||
COPY meshchatx/src/backend/lxst_pyogg_ctypes_compat.py ./meshchatx/src/backend/lxst_pyogg_ctypes_compat.py
|
||||
# Third-party deps layer: stable across app-only updates when uv.lock is unchanged.
|
||||
# --inexact keeps setuptools/jaraco.context already in the venv (cffi needs them).
|
||||
RUN uv sync --no-group dev --no-install-project --inexact && \
|
||||
rm -rf /root/.cache/pip /root/.cache/uv && \
|
||||
pip install --no-cache-dir --upgrade "setuptools" "jaraco.context>=6.1.0" && \
|
||||
python scripts/patch_lxst_pyogg_ogg_ctypes.py && \
|
||||
python scripts/patch_lxst_codec2_optional.py && \
|
||||
rm -rf /opt/venv/lib/python*/site-packages/LXST/Platforms/android && \
|
||||
find /opt/venv -type d \( -name tests -o -name test -o -name __pycache__ \) -prune -exec rm -rf {} + && \
|
||||
python -m compileall -q /opt/venv && \
|
||||
cp -a /opt/venv /opt/venv-deps
|
||||
|
||||
COPY scripts/docker/prepare-venv.sh scripts/docker/prepare-venv.sh
|
||||
COPY scripts/docker/build-app-overlay.sh scripts/docker/build-app-overlay.sh
|
||||
ENV MESHCHATX_DOCKER_SKIP_MUSL_FILTERLIB=1
|
||||
RUN sh scripts/docker/prepare-venv.sh
|
||||
COPY meshchatx ./meshchatx
|
||||
COPY --from=build-frontend /src/meshchatx/public ./meshchatx/public
|
||||
|
||||
# App overlay: meshchatx + vendored packages + console scripts (changes often).
|
||||
RUN pip install --no-cache-dir . && \
|
||||
PYVER="$(python -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')" && \
|
||||
SP="/opt/venv/lib/python${PYVER}/site-packages" && \
|
||||
OUT="/opt/app-overlay" && \
|
||||
mkdir -p "${OUT}/lib/python${PYVER}/site-packages" "${OUT}/bin" && \
|
||||
for pkg in meshchatx lxmfy rns_filesync; do \
|
||||
cp -a "${SP}/${pkg}" "${OUT}/lib/python${PYVER}/site-packages/"; \
|
||||
done && \
|
||||
cp -a "${SP}"/reticulum_meshchatx*.dist-info "${OUT}/lib/python${PYVER}/site-packages/" && \
|
||||
for cmd in meshchat meshchatx meshchatx-repository-http lxmfy rns-filesync; do \
|
||||
cp -a "/opt/venv/bin/${cmd}" "${OUT}/bin/"; \
|
||||
done && \
|
||||
find "${OUT}" -type d -name __pycache__ -prune -exec rm -rf {} + && \
|
||||
python -m compileall -q "${OUT}/lib/python${PYVER}/site-packages"
|
||||
RUN sh scripts/docker/build-app-overlay.sh
|
||||
|
||||
FROM ${PYTHON_RUNTIME_IMAGE}
|
||||
|
||||
USER root
|
||||
RUN apk add --no-cache opus libffi shadow && \
|
||||
pip install --no-cache-dir --upgrade "pip>=26.0" "setuptools" "jaraco.context>=6.1.0" && \
|
||||
rm -rf /root/.cache/pip && \
|
||||
groupadd -g 1000 meshchat && \
|
||||
useradd --uid 1000 --gid 1000 --create-home --home-dir /home/meshchat \
|
||||
--shell /sbin/nologin meshchat && \
|
||||
mkdir -p /config && chown meshchat:meshchat /config
|
||||
|
||||
COPY scripts/docker/runtime-setup-chainguard.sh /tmp/runtime-setup-chainguard.sh
|
||||
RUN sh /tmp/runtime-setup-chainguard.sh && rm /tmp/runtime-setup-chainguard.sh
|
||||
COPY --from=builder --chown=meshchat:meshchat /opt/venv-deps /opt/venv
|
||||
COPY --from=builder --chown=meshchat:meshchat /opt/app-overlay/ /opt/venv/
|
||||
COPY scripts/docker_entrypoint_chainguard.py /docker-entrypoint.py
|
||||
|
||||
# Declare after COPY so per-build OCI values do not invalidate runtime or venv layers.
|
||||
ARG OCI_REVISION=""
|
||||
ARG OCI_VERSION=""
|
||||
ARG OCI_CREATED=""
|
||||
|
||||
LABEL org.opencontainers.image.source="https://github.com/Quad4-Software/MeshChatX"
|
||||
LABEL org.opencontainers.image.description="MeshChatX is a all in one Reticulum client."
|
||||
LABEL org.opencontainers.image.description="MeshChatX is an all-in-one Reticulum client."
|
||||
LABEL org.opencontainers.image.licenses="MIT AND 0BSD"
|
||||
LABEL org.opencontainers.image.authors="Quad4"
|
||||
LABEL org.opencontainers.image.revision="${OCI_REVISION}"
|
||||
|
|
@ -129,4 +83,4 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=90s --retries=3 \
|
|||
CMD ["python", "-c", "import ssl, urllib.request; urllib.request.urlopen('https://127.0.0.1:8000/api/v1/status', context=ssl._create_unverified_context())"]
|
||||
|
||||
ENTRYPOINT ["/usr/bin/python", "/docker-entrypoint.py"]
|
||||
CMD ["/opt/venv/bin/meshchatx", "--host=0.0.0.0", "--reticulum-config-dir=/config/.reticulum", "--storage-dir=/config/.reticulum-meshchatx", "--headless"]
|
||||
CMD ["/opt/venv/bin/meshchatx", "--host=0.0.0.0", "--reticulum-config-dir=/config/.reticulum", "--storage-dir=/config/.reticulum-meshchatx", "--headless"]
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ Notes:
|
|||
|
||||
- **Docker Hub:** `quad4io/meshchatx`
|
||||
- **GHCR:** `ghcr.io/quad4-software/meshchatx`
|
||||
- **Variants:** default tags (for example `:latest`) are the standard Alpine image. Use `-hardened` for the Chainguard/Wolfi image, or `-extra` for Alpine plus **i2pd** and **yggdrasil** (for example `:latest-extra`, built from the same `Dockerfile` with `VARIANT=extra`).
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ One source tree produces:
|
|||
|
||||
- Development runs via `uv run python -m meshchatx.meshchat`
|
||||
- Python wheels with bundled `public/` assets
|
||||
- Container images (Dockerfile and hardened variants)
|
||||
- Container images (Alpine Dockerfile with standard/extra VARIANT, plus hardened Chainguard)
|
||||
- Electron builds for Windows, macOS, and Linux
|
||||
- Android APK via Chaquopy
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ MeshChatX can be installed in several ways. All release artifacts that ship the
|
|||
| Android APK | Yes | Phones, tablets, Meta Quest sideload |
|
||||
| From source | Built locally | Development and custom builds |
|
||||
|
||||
Release images are published to Docker Hub (`quad4io/meshchatx`) and GHCR (`ghcr.io/quad4-software/meshchatx`).
|
||||
Release images are published to Docker Hub (`quad4io/meshchatx`) and GHCR (`ghcr.io/quad4-software/meshchatx`). Tag suffixes: none for the standard Alpine image, `-hardened` for Chainguard/Wolfi, `-extra` for Alpine plus i2pd and yggdrasil (`VARIANT=extra` on the same Dockerfile).
|
||||
|
||||
## Docker
|
||||
|
||||
|
|
|
|||
BIN
meshchatx.rsm
BIN
meshchatx.rsm
Binary file not shown.
|
|
@ -247,6 +247,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
@reference "../style.css";
|
||||
.tutorial-privacy {
|
||||
@apply space-y-4;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
@reference "../../style.css";
|
||||
.setting-toggle {
|
||||
@apply relative flex flex-row-reverse items-start gap-3 rounded-2xl border border-gray-200 dark:border-zinc-800 bg-white/70 dark:bg-zinc-900/70 px-3 py-3;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ One source tree produces:
|
|||
|
||||
- Development runs via `uv run python -m meshchatx.meshchat`
|
||||
- Python wheels with bundled `public/` assets
|
||||
- Container images (Dockerfile and hardened variants)
|
||||
- Container images (Alpine Dockerfile with standard/extra VARIANT, plus hardened Chainguard)
|
||||
- Electron builds for Windows, macOS, and Linux
|
||||
- Android APK via Chaquopy
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ MeshChatX can be installed in several ways. All release artifacts that ship the
|
|||
| Android APK | Yes | Phones, tablets, Meta Quest sideload |
|
||||
| From source | Built locally | Development and custom builds |
|
||||
|
||||
Release images are published to Docker Hub (`quad4io/meshchatx`) and GHCR (`ghcr.io/quad4-software/meshchatx`).
|
||||
Release images are published to Docker Hub (`quad4io/meshchatx`) and GHCR (`ghcr.io/quad4-software/meshchatx`). Tag suffixes: none for the standard Alpine image, `-hardened` for Chainguard/Wolfi, `-extra` for Alpine plus i2pd and yggdrasil (`VARIANT=extra` on the same Dockerfile).
|
||||
|
||||
## Docker
|
||||
|
||||
|
|
|
|||
29
scripts/docker/build-app-overlay.sh
Executable file
29
scripts/docker/build-app-overlay.sh
Executable file
|
|
@ -0,0 +1,29 @@
|
|||
#!/bin/sh
|
||||
# SPDX-License-Identifier: 0BSD
|
||||
# Install the project into /opt/venv and copy a thin app overlay for image layering.
|
||||
# Requires PATH pointing at /opt/venv/bin and built frontend under meshchatx/public.
|
||||
set -eu
|
||||
|
||||
VENV="${MESHCHATX_DOCKER_VENV:-/opt/venv}"
|
||||
OUT="${MESHCHATX_DOCKER_APP_OVERLAY:-/opt/app-overlay}"
|
||||
|
||||
pip install --no-cache-dir .
|
||||
|
||||
PYVER="$(python -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')"
|
||||
SP="${VENV}/lib/python${PYVER}/site-packages"
|
||||
|
||||
rm -rf "${OUT}"
|
||||
mkdir -p "${OUT}/lib/python${PYVER}/site-packages" "${OUT}/bin"
|
||||
|
||||
for pkg in meshchatx lxmfy rns_filesync; do
|
||||
cp -a "${SP}/${pkg}" "${OUT}/lib/python${PYVER}/site-packages/"
|
||||
done
|
||||
|
||||
cp -a "${SP}"/reticulum_meshchatx*.dist-info "${OUT}/lib/python${PYVER}/site-packages/"
|
||||
|
||||
for cmd in meshchat meshchatx meshchatx-repository-http lxmfy rns-filesync; do
|
||||
cp -a "${VENV}/bin/${cmd}" "${OUT}/bin/"
|
||||
done
|
||||
|
||||
find "${OUT}" -type d -name __pycache__ -prune -exec rm -rf {} +
|
||||
python -m compileall -q "${OUT}/lib/python${PYVER}/site-packages"
|
||||
23
scripts/docker/build-frontend.sh
Executable file
23
scripts/docker/build-frontend.sh
Executable file
|
|
@ -0,0 +1,23 @@
|
|||
#!/bin/sh
|
||||
# SPDX-License-Identifier: 0BSD
|
||||
# Build MeshChatX frontend assets inside a Node image stage.
|
||||
# Expects WORKDIR with package manifests, patches, scripts, docs, and frontend tree.
|
||||
set -eu
|
||||
|
||||
mkdir -p /tmp/go-cache /tmp/go-tmp
|
||||
export GOCACHE="${GOCACHE:-/tmp/go-cache}"
|
||||
export GOTMPDIR="${GOTMPDIR:-/tmp/go-tmp}"
|
||||
|
||||
PNPM_VERSION="${MESHCHATX_PNPM_VERSION:-11.1.2}"
|
||||
|
||||
npm install -g "pnpm@${PNPM_VERSION}"
|
||||
pnpm config set verify-store-integrity true
|
||||
pnpm install --frozen-lockfile
|
||||
MESHCHATX_REQUIRE_VISUALISER_WASM=1 pnpm run build-frontend
|
||||
|
||||
test -s meshchatx/src/frontend/public/vendor/visualiser-wasm/visualiser.wasm
|
||||
test -s meshchatx/src/frontend/public/vendor/visualiser-wasm/wasm_exec.js
|
||||
test -s meshchatx/src/frontend/public/vendor/micron-parser-go/micron-parser-go.wasm
|
||||
test -s meshchatx/src/frontend/public/vendor/micron-parser-go/wasm_exec.js
|
||||
|
||||
pnpm run build-docs
|
||||
7
scripts/docker/builder-apk-alpine.sh
Executable file
7
scripts/docker/builder-apk-alpine.sh
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
# SPDX-License-Identifier: 0BSD
|
||||
# Alpine builder-stage compile toolchain for uv sync and LXST musl bake.
|
||||
set -eu
|
||||
|
||||
apk upgrade --no-cache
|
||||
apk add --no-cache gcc g++ musl-dev linux-headers python3-dev libffi-dev openssl-dev git
|
||||
6
scripts/docker/builder-apk-chainguard.sh
Executable file
6
scripts/docker/builder-apk-chainguard.sh
Executable file
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
# SPDX-License-Identifier: 0BSD
|
||||
# Chainguard/Wolfi builder-stage compile toolchain.
|
||||
set -eu
|
||||
|
||||
apk add --no-cache build-base git pkgconf openssl-dev libffi-dev linux-headers
|
||||
29
scripts/docker/prepare-venv.sh
Executable file
29
scripts/docker/prepare-venv.sh
Executable file
|
|
@ -0,0 +1,29 @@
|
|||
#!/bin/sh
|
||||
# SPDX-License-Identifier: 0BSD
|
||||
# Sync third-party deps into /opt/venv, apply LXST patches, snapshot /opt/venv-deps.
|
||||
# Requires PATH pointing at /opt/venv/bin and project files already copied to WORKDIR.
|
||||
# Set MESHCHATX_DOCKER_SKIP_MUSL_FILTERLIB=1 on glibc (hardened) builds.
|
||||
set -eu
|
||||
|
||||
VENV="${MESHCHATX_DOCKER_VENV:-/opt/venv}"
|
||||
VENV_DEPS="${MESHCHATX_DOCKER_VENV_DEPS:-/opt/venv-deps}"
|
||||
|
||||
uv sync --no-group dev --no-install-project --inexact
|
||||
rm -rf /root/.cache/pip /root/.cache/uv
|
||||
pip install --no-cache-dir --upgrade "setuptools" "jaraco.context>=6.1.0"
|
||||
|
||||
python scripts/patch_lxst_pyogg_ogg_ctypes.py
|
||||
python scripts/patch_lxst_codec2_optional.py
|
||||
|
||||
if [ "${MESHCHATX_DOCKER_SKIP_MUSL_FILTERLIB:-0}" != "1" ]; then
|
||||
python scripts/docker-bake-lxst-filterlib-musl.py
|
||||
fi
|
||||
|
||||
rm -rf "${VENV}"/lib/python*/site-packages/LXST/Platforms/android
|
||||
find "${VENV}" -type d \( -name tests -o -name test -o -name __pycache__ \) -prune -exec rm -rf {} +
|
||||
|
||||
PYVER="$(python -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')"
|
||||
python -m compileall -q "${VENV}/lib/python${PYVER}/site-packages"
|
||||
|
||||
rm -rf "${VENV_DEPS}"
|
||||
cp -a "${VENV}" "${VENV_DEPS}"
|
||||
14
scripts/docker/runtime-setup-chainguard.sh
Executable file
14
scripts/docker/runtime-setup-chainguard.sh
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/sh
|
||||
# SPDX-License-Identifier: 0BSD
|
||||
# Chainguard/Wolfi final-stage packages, pip bootstrap, and meshchat user.
|
||||
set -eu
|
||||
|
||||
apk add --no-cache opus libffi shadow
|
||||
pip install --no-cache-dir --upgrade "pip>=26.0" "setuptools" "jaraco.context>=6.1.0"
|
||||
rm -rf /root/.cache/pip
|
||||
|
||||
groupadd -g 1000 meshchat
|
||||
useradd --uid 1000 --gid 1000 --create-home --home-dir /home/meshchat \
|
||||
--shell /sbin/nologin meshchat
|
||||
mkdir -p /config
|
||||
chown meshchat:meshchat /config
|
||||
31
scripts/docker/runtime-setup.sh
Executable file
31
scripts/docker/runtime-setup.sh
Executable file
|
|
@ -0,0 +1,31 @@
|
|||
#!/bin/sh
|
||||
# SPDX-License-Identifier: 0BSD
|
||||
# Alpine final-stage packages, pip bootstrap, and meshchat user.
|
||||
# Usage: runtime-setup.sh [standard|extra]
|
||||
set -eu
|
||||
|
||||
VARIANT="${1:-${VARIANT:-standard}}"
|
||||
|
||||
apk upgrade --no-cache
|
||||
apk add --no-cache opusfile libffi espeak-ng su-exec
|
||||
|
||||
case "${VARIANT}" in
|
||||
standard) ;;
|
||||
extra)
|
||||
apk add --no-cache i2pd
|
||||
# yggdrasil post-install runs modprobe which fails without host modules
|
||||
apk add --no-cache --no-scripts yggdrasil
|
||||
;;
|
||||
*)
|
||||
echo "runtime-setup.sh: unknown VARIANT '${VARIANT}' (expected standard or extra)" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
python -m pip install --no-cache-dir --upgrade "pip>=26.0" "setuptools" "jaraco.context>=6.1.0"
|
||||
rm -rf /root/.cache/pip
|
||||
|
||||
addgroup -g 1000 meshchat
|
||||
adduser -u 1000 -G meshchat -S meshchat
|
||||
mkdir -p /config
|
||||
chown meshchat:meshchat /config
|
||||
Loading…
Add table
Add a link
Reference in a new issue