Docker use latest libreoffice and fonts (#5482)

# Description of Changes

<!--
Please provide a summary of the changes, including:

- What was changed
- Why the change was made
- Any challenges encountered

Closes #(issue_number)
-->

---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### Translations (if applicable)

- [ ] I ran
[`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
This commit is contained in:
Anthony Stirling 2026-01-15 15:01:10 +00:00 committed by GitHub
parent 884801ea36
commit 8afbd0afed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 83 additions and 90 deletions

View File

@ -194,81 +194,44 @@ jobs:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_API }}
- name: Get commit hashes for frontend and backend
id: commit-hashes
- name: Get commit hash for app
id: commit-hash
run: |
# Get last commit that touched the frontend folder, docker/frontend, or docker/compose
FRONTEND_HASH=$(git log -1 --format="%H" -- frontend/ docker/frontend/ docker/compose/ 2>/dev/null || echo "")
if [ -z "$FRONTEND_HASH" ]; then
FRONTEND_HASH="no-frontend-changes"
# Get last commit that touched the application code
APP_HASH=$(git log -1 --format="%H" -- . 2>/dev/null || echo "")
if [ -z "$APP_HASH" ]; then
APP_HASH="no-changes"
fi
# Get last commit that touched backend code, docker/backend, or docker/compose
BACKEND_HASH=$(git log -1 --format="%H" -- app/ docker/backend/ docker/compose/ 2>/dev/null || echo "")
if [ -z "$BACKEND_HASH" ]; then
BACKEND_HASH="no-backend-changes"
fi
echo "App hash: $APP_HASH"
echo "app_hash=$APP_HASH" >> $GITHUB_OUTPUT
echo "Frontend hash: $FRONTEND_HASH"
echo "Backend hash: $BACKEND_HASH"
echo "frontend_hash=$FRONTEND_HASH" >> $GITHUB_OUTPUT
echo "backend_hash=$BACKEND_HASH" >> $GITHUB_OUTPUT
# Short hashes for tags
if [ "$FRONTEND_HASH" = "no-frontend-changes" ]; then
echo "frontend_short=no-frontend" >> $GITHUB_OUTPUT
# Short hash for tags
if [ "$APP_HASH" = "no-changes" ]; then
echo "app_short=no-changes" >> $GITHUB_OUTPUT
else
echo "frontend_short=${FRONTEND_HASH:0:8}" >> $GITHUB_OUTPUT
echo "app_short=${APP_HASH:0:8}" >> $GITHUB_OUTPUT
fi
if [ "$BACKEND_HASH" = "no-backend-changes" ]; then
echo "backend_short=no-backend" >> $GITHUB_OUTPUT
else
echo "backend_short=${BACKEND_HASH:0:8}" >> $GITHUB_OUTPUT
fi
- name: Check if frontend image exists
id: check-frontend
- name: Check if image exists
id: check-image
run: |
if docker manifest inspect ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }} >/dev/null 2>&1; then
if docker manifest inspect ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-${{ steps.commit-hash.outputs.app_short }} >/dev/null 2>&1; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "Frontend image already exists, skipping build"
echo "Image already exists, skipping build"
else
echo "exists=false" >> $GITHUB_OUTPUT
echo "Frontend image needs to be built"
echo "Image needs to be built"
fi
- name: Check if backend image exists
id: check-backend
run: |
if docker manifest inspect ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }} >/dev/null 2>&1; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "Backend image already exists, skipping build"
else
echo "exists=false" >> $GITHUB_OUTPUT
echo "Backend image needs to be built"
fi
- name: Build and push V2 frontend image
if: steps.check-frontend.outputs.exists == 'false'
- name: Build and push V2 image
if: steps.check-image.outputs.exists == 'false'
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
context: .
file: ./docker/frontend/Dockerfile
file: ./docker/embedded/Dockerfile
push: true
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }}
build-args: VERSION_TAG=v2-alpha
platforms: linux/amd64
- name: Build and push V2 backend image
if: steps.check-backend.outputs.exists == 'false'
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
context: .
file: ./docker/backend/Dockerfile
push: true
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }}
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-${{ steps.commit-hash.outputs.app_short }}
build-args: VERSION_TAG=v2-alpha
platforms: linux/amd64
@ -283,17 +246,16 @@ jobs:
run: |
# Use same port strategy as regular PRs - just the PR number
V2_PORT=${{ needs.check-pr.outputs.pr_number }}
BACKEND_PORT=$((V2_PORT + 10000)) # Backend on higher port to avoid conflicts
# Create docker-compose for V2 with separate frontend and backend
# Create docker-compose for V2 with unified embedded image
cat > docker-compose.yml << EOF
version: '3.3'
services:
stirling-pdf-v2-backend:
container_name: stirling-pdf-v2-backend-pr-${{ needs.check-pr.outputs.pr_number }}
image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }}
stirling-pdf-v2:
container_name: stirling-pdf-v2-pr-${{ needs.check-pr.outputs.pr_number }}
image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-${{ steps.commit-hash.outputs.app_short }}
ports:
- "${BACKEND_PORT}:8080" # Backend API port
- "${V2_PORT}:8080"
volumes:
- /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}/data:/usr/share/tessdata:rw
- /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}/config:/configs:rw
@ -305,7 +267,7 @@ jobs:
SECURITY_INITIALLOGIN_PASSWORD: "${{ secrets.TEST_LOGIN_PASSWORD }}"
SYSTEM_DEFAULTLOCALE: en-GB
UI_APPNAME: "Stirling-PDF V2 PR#${{ needs.check-pr.outputs.pr_number }}"
UI_HOMEDESCRIPTION: "V2 PR#${{ needs.check-pr.outputs.pr_number }} - Frontend/Backend Split Architecture"
UI_HOMEDESCRIPTION: "V2 PR#${{ needs.check-pr.outputs.pr_number }} - Embedded Architecture"
UI_APPNAMENAVBAR: "V2 PR#${{ needs.check-pr.outputs.pr_number }}"
SYSTEM_MAXFILESIZE: "100"
METRICS_ENABLED: "true"
@ -313,17 +275,6 @@ jobs:
SWAGGER_SERVER_URL: "https://${V2_PORT}.ssl.stirlingpdf.cloud"
baseUrl: "https://${V2_PORT}.ssl.stirlingpdf.cloud"
restart: on-failure:5
stirling-pdf-v2-frontend:
container_name: stirling-pdf-v2-frontend-pr-${{ needs.check-pr.outputs.pr_number }}
image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }}
ports:
- "${V2_PORT}:80" # Frontend port (same as regular PRs)
environment:
VITE_API_BASE_URL: "http://${{ secrets.NEW_VPS_HOST }}:${BACKEND_PORT}"
depends_on:
- stirling-pdf-v2-backend
restart: on-failure:5
EOF
# Deploy to VPS
@ -339,15 +290,15 @@ jobs:
# Stop any existing container and clean up
cd /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}
docker-compose down --remove-orphans 2>/dev/null || true
# Start the new container
docker-compose pull
docker-compose up -d
# Clean up unused Docker resources to save space
docker system prune -af --volumes || true
# Clean up old backend/frontend images (older than 2 weeks)
# Clean up old images (older than 2 weeks)
docker image prune -af --filter "until=336h" --filter "label!=keep=true" || true
ENDSSH
@ -383,7 +334,7 @@ jobs:
const httpsUrl = `https://${v2Port}.ssl.stirlingpdf.cloud`;
const commentBody = `## 🚀 V2 Auto-Deployment Complete!\n\n` +
`Your V2 PR with the new frontend/backend split architecture has been deployed!\n\n` +
`Your V2 PR with embedded architecture has been deployed!\n\n` +
`🔗 **Direct Test URL (non-SSL)** [${deploymentUrl}](${deploymentUrl})\n\n` +
`🔐 **Secure HTTPS URL**: [${httpsUrl}](${httpsUrl})\n\n` +
`_This deployment will be automatically cleaned up when the PR is closed._\n\n` +
@ -473,9 +424,8 @@ jobs:
# Remove V2 PR-specific directories
rm -rf /stirling/V2-PR-${{ github.event.pull_request.number }}
# Clean up V2 containers by name (in case compose cleanup missed them)
docker rm -f stirling-pdf-v2-frontend-pr-${{ github.event.pull_request.number }} || true
docker rm -f stirling-pdf-v2-backend-pr-${{ github.event.pull_request.number }} || true
# Clean up V2 container by name (in case compose cleanup missed it)
docker rm -f stirling-pdf-v2-pr-${{ github.event.pull_request.number }} || true
echo "V2 cleanup completed"
else

View File

@ -42,6 +42,9 @@ FROM debian:stable-slim@sha256:f6681102cd18b4c0c4720a77b602498f4bdcf701c8fc02776
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
ENV DEBIAN_FRONTEND=noninteractive
ENV LANG=C.UTF-8 \
LC_ALL=C.UTF-8
ENV TESS_BASE_PATH=/usr/share/tesseract-ocr/5/tessdata
# Install core runtime dependencies + tools required by Stirling-PDF features
@ -49,7 +52,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates tzdata tini bash fontconfig \
openjdk-21-jre-headless \
ffmpeg poppler-utils ocrmypdf imagemagick fontforge ghostscript \
libreoffice-nogui libreoffice-java-common \
fonts-dejavu \
fonts-liberation fonts-liberation2 \
fonts-crosextra-caladea fonts-crosextra-carlito \
fonts-linuxlibertine \
fonts-noto-core fonts-noto-cjk fonts-noto-mono fonts-noto-ui-core \
fonts-noto-color-emoji \
ttf-wqy-zenhei \
fonts-arphic-ukai fonts-arphic-uming \
python3 python3-venv python3-uno \
tesseract-ocr tesseract-ocr-eng tesseract-ocr-deu tesseract-ocr-fra \
tesseract-ocr-por tesseract-ocr-chi-sim \
@ -75,6 +85,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
&& apt-get autoremove -y \
&& rm -rf /var/lib/apt/lists/*
RUN set -eux; \
. /etc/os-release; \
echo "deb http://deb.debian.org/debian ${VERSION_CODENAME}-backports main" > /etc/apt/sources.list.d/backports.list; \
apt-get update; \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends -t ${VERSION_CODENAME}-backports \
libreoffice libreoffice-java-common; \
rm -rf /var/lib/apt/lists/*; \
libreoffice --version
# Make ebook-convert available in PATH
RUN ln -sf /opt/calibre/ebook-convert /usr/bin/ebook-convert \
&& /opt/calibre/ebook-convert --version
@ -140,6 +159,7 @@ ENV VERSION_TAG=$VERSION_TAG \
PGID=${PGID} \
UMASK=022 \
UNO_PATH=/usr/lib/libreoffice/program \
LIBREOFFICE_BIN_PATH=/usr/lib/libreoffice/program/soffice.bin \
STIRLING_TEMPFILES_DIRECTORY=/tmp/stirling-pdf \
TMPDIR=/tmp/stirling-pdf \
TEMP=/tmp/stirling-pdf \
@ -153,8 +173,9 @@ RUN python3 -m venv /opt/venv --system-site-packages \
&& /opt/venv/bin/python -c "import cv2; print('OpenCV version:', cv2.__version__)"
# Separate venv for unoserver (keeps it isolated)
ARG UNOSERVER_VERSION=3.6
RUN python3 -m venv /opt/unoserver-venv --system-site-packages \
&& /opt/unoserver-venv/bin/pip install --no-cache-dir unoserver
&& /opt/unoserver-venv/bin/pip install --no-cache-dir "unoserver==${UNOSERVER_VERSION}"
# Make unoserver tools available in main venv PATH
RUN ln -sf /opt/unoserver-venv/bin/unoconvert /opt/venv/bin/unoconvert \

View File

@ -42,6 +42,9 @@ FROM debian:stable-slim@sha256:f6681102cd18b4c0c4720a77b602498f4bdcf701c8fc02776
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
ENV DEBIAN_FRONTEND=noninteractive
ENV LANG=C.UTF-8 \
LC_ALL=C.UTF-8
ENV TESS_BASE_PATH=/usr/share/tesseract-ocr/5/tessdata
# Install core runtime dependencies + tools required by Stirling-PDF features + extra fonts for fat version
@ -49,15 +52,20 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates tzdata tini bash fontconfig \
openjdk-21-jre-headless \
ffmpeg poppler-utils ocrmypdf imagemagick fontforge ghostscript \
libreoffice-nogui libreoffice-java-common \
fonts-dejavu \
fonts-liberation fonts-liberation2 \
fonts-crosextra-caladea fonts-crosextra-carlito \
fonts-linuxlibertine \
fonts-noto-core fonts-noto-cjk fonts-noto-mono fonts-noto-ui-core \
fonts-noto-color-emoji \
ttf-wqy-zenhei \
fonts-arphic-ukai fonts-arphic-uming \
fonts-freefont-ttf fonts-terminus \
python3 python3-venv python3-uno \
tesseract-ocr tesseract-ocr-eng tesseract-ocr-deu tesseract-ocr-fra \
tesseract-ocr-por tesseract-ocr-chi-sim \
libcairo2 libpango-1.0-0 libpangoft2-1.0-0 libgdk-pixbuf-2.0-0 \
gosu unpaper qpdf \
# Extra fonts for fat/air-gapped version
fonts-dejavu fonts-liberation fonts-noto fonts-noto-cjk fonts-noto-color-emoji \
fonts-freefont-ttf fonts-terminus fonts-linuxlibertine \
# AWT headless support (required for some Java graphics operations)
libfreetype6 libfontconfig1 libx11-6 libxt6 libxext6 libxrender1 libxtst6 libxi6 \
libxinerama1 libxkbcommon0 libxkbfile1 libsm6 libice6 \
@ -78,6 +86,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
&& apt-get autoremove -y \
&& rm -rf /var/lib/apt/lists/*
RUN set -eux; \
. /etc/os-release; \
echo "deb http://deb.debian.org/debian ${VERSION_CODENAME}-backports main" > /etc/apt/sources.list.d/backports.list; \
apt-get update; \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends -t ${VERSION_CODENAME}-backports \
libreoffice libreoffice-java-common; \
rm -rf /var/lib/apt/lists/*; \
libreoffice --version
# Make ebook-convert available in PATH
RUN ln -sf /opt/calibre/ebook-convert /usr/bin/ebook-convert \
&& /opt/calibre/ebook-convert --version
@ -145,6 +162,7 @@ ENV VERSION_TAG=$VERSION_TAG \
FAT_DOCKER=true \
INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false \
UNO_PATH=/usr/lib/libreoffice/program \
LIBREOFFICE_BIN_PATH=/usr/lib/libreoffice/program/soffice.bin \
STIRLING_TEMPFILES_DIRECTORY=/tmp/stirling-pdf \
TMPDIR=/tmp/stirling-pdf \
TEMP=/tmp/stirling-pdf \
@ -158,8 +176,9 @@ RUN python3 -m venv /opt/venv --system-site-packages \
&& /opt/venv/bin/python -c "import cv2; print('OpenCV version:', cv2.__version__)"
# Separate venv for unoserver (keeps it isolated)
ARG UNOSERVER_VERSION=3.6
RUN python3 -m venv /opt/unoserver-venv --system-site-packages \
&& /opt/unoserver-venv/bin/pip install --no-cache-dir unoserver
&& /opt/unoserver-venv/bin/pip install --no-cache-dir "unoserver==${UNOSERVER_VERSION}"
# Make unoserver tools available in main venv PATH
RUN ln -sf /opt/unoserver-venv/bin/unoconvert /opt/venv/bin/unoconvert \

View File

@ -38,6 +38,9 @@ RUN DISABLE_ADDITIONAL_FEATURES=true \
# Stage 2: Runtime image
FROM alpine:3.23.2@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62
ENV LANG=C.UTF-8 \
LC_ALL=C.UTF-8
ARG VERSION_TAG
# Labels