# Description of Changes <img width="1569" height="980" alt="image" src="https://github.com/user-attachments/assets/dca1c227-ed84-4393-97a1-e3ce6eb1620b" /> <img width="1596" height="935" alt="image" src="https://github.com/user-attachments/assets/2003e1be-034a-4cbb-869e-6d5d912ab61d" /> <img width="1543" height="997" alt="image" src="https://github.com/user-attachments/assets/fe0c4f4b-eeee-4db4-a041-e554f350255a" /> --- ## 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. |
||
|---|---|---|
| .. | ||
| build.sh | ||
| entrypoint.sh | ||
| nginx.conf | ||
| README.md | ||
Stirling-PDF Unified Container
Single Docker container that can run as frontend + backend, frontend only, or backend only using the MODE environment variable.
Quick Start
MODE=BOTH (Default)
Single container with both frontend and backend on port 8080:
docker run -p 8080:8080 \
-e MODE=BOTH \
stirlingtools/stirling-pdf:unified
Access at: http://localhost:8080
MODE=FRONTEND
Frontend only, connecting to separate backend:
docker run -p 8080:8080 \
-e MODE=FRONTEND \
-e VITE_API_BASE_URL=http://backend:8080 \
stirlingtools/stirling-pdf:unified
MODE=BACKEND
Backend API only:
docker run -p 8080:8080 \
-e MODE=BACKEND \
stirlingtools/stirling-pdf:unified
Access API at: http://localhost:8080/api
Swagger UI at: http://localhost:8080/swagger-ui/index.html
Architecture
MODE=BOTH (Default)
┌─────────────────────────────────────┐
│ Port 8080 (External) │
│ ┌───────────────────────────────┐ │
│ │ Nginx │ │
│ │ • Serves frontend (/) │ │
│ │ • Proxies /api/* → backend │ │
│ └───────────┬───────────────────┘ │
│ │ │
│ ┌───────────▼───────────────────┐ │
│ │ Backend (Internal 8081) │ │
│ │ • Spring Boot │ │
│ │ • PDF Processing │ │
│ │ • UnoServer │ │
│ └───────────────────────────────┘ │
└─────────────────────────────────────┘
MODE=FRONTEND
┌─────────────────────────────┐ ┌──────────────────┐
│ Frontend Container │ │ Backend │
│ Port 8080 │ │ (External) │
│ ┌───────────────────────┐ │ │ │
│ │ Nginx │ │──────▶ :8080/api │
│ │ • Serves frontend │ │ │ │
│ │ • Proxies to backend │ │ │ │
│ └───────────────────────┘ │ └──────────────────┘
└─────────────────────────────┘
MODE=BACKEND
┌─────────────────────────────┐
│ Backend Container │
│ Port 8080 │
│ ┌───────────────────────┐ │
│ │ Spring Boot │ │
│ │ • API Endpoints │ │
│ │ • PDF Processing │ │
│ │ • UnoServer │ │
│ └───────────────────────┘ │
└─────────────────────────────┘
Environment Variables
MODE Configuration
| Variable | Values | Default | Description |
|---|---|---|---|
MODE |
BOTH, FRONTEND, BACKEND |
BOTH |
Container operation mode |
MODE=BOTH Specific
| Variable | Default | Description |
|---|---|---|
BACKEND_INTERNAL_PORT |
8081 |
Internal port for backend when MODE=BOTH |
MODE=FRONTEND Specific
| Variable | Default | Description |
|---|---|---|
VITE_API_BASE_URL |
http://backend:8080 |
Backend URL for API proxying |
Standard Configuration
All modes support standard Stirling-PDF environment variables:
DISABLE_ADDITIONAL_FEATURES- Enable/disable OCR and LibreOffice featuresDOCKER_ENABLE_SECURITY- Enable authenticationPUID/PGID- User/Group IDsSYSTEM_MAXFILESIZE- Max upload size (MB)TESSERACT_LANGS- Comma-separated OCR language codesJAVA_CUSTOM_OPTS- Additional JVM options
See full configuration docs at: https://docs.stirlingpdf.com
Docker Compose Examples
Example 1: All-in-One (MODE=BOTH)
File: docker/compose/docker-compose-unified-both.yml
services:
stirling-pdf:
image: stirlingtools/stirling-pdf:unified
ports:
- "8080:8080"
volumes:
- ./data:/usr/share/tessdata:rw
- ./config:/configs:rw
environment:
MODE: BOTH
restart: unless-stopped
Example 2: Separate Frontend & Backend
File: docker/compose/docker-compose-unified-frontend.yml
services:
backend:
image: stirlingtools/stirling-pdf:unified
ports:
- "8081:8080"
environment:
MODE: BACKEND
volumes:
- ./data:/usr/share/tessdata:rw
- ./config:/configs:rw
frontend:
image: stirlingtools/stirling-pdf:unified
ports:
- "8080:8080"
environment:
MODE: FRONTEND
VITE_API_BASE_URL: http://backend:8080
depends_on:
- backend
Example 3: Backend API Only
File: docker/compose/docker-compose-unified-backend.yml
services:
stirling-pdf-api:
image: stirlingtools/stirling-pdf:unified
ports:
- "8080:8080"
environment:
MODE: BACKEND
volumes:
- ./data:/usr/share/tessdata:rw
- ./config:/configs:rw
restart: unless-stopped
Building the Image
# From repository root
docker build -t stirlingtools/stirling-pdf:unified -f docker/Dockerfile.unified .
Build Arguments
| Argument | Description |
|---|---|
VERSION_TAG |
Version tag for the image |
Example:
docker build \
--build-arg VERSION_TAG=v1.0.0 \
-t stirlingtools/stirling-pdf:unified \
-f docker/Dockerfile.unified .
Use Cases
1. Simple Deployment (MODE=BOTH)
- Best for: Personal use, small teams, simple deployments
- Pros: Single container, easy setup, minimal configuration
- Cons: Frontend and backend scale together
2. Scaled Frontend (MODE=FRONTEND + BACKEND)
- Best for: High traffic, need to scale frontend independently
- Pros: Scale frontend containers separately, CDN-friendly
- Example:
services: backend: image: stirlingtools/stirling-pdf:unified environment: MODE: BACKEND deploy: replicas: 1 frontend: image: stirlingtools/stirling-pdf:unified environment: MODE: FRONTEND VITE_API_BASE_URL: http://backend:8080 deploy: replicas: 5 # Scale frontend independently
3. API-Only (MODE=BACKEND)
- Best for: Headless deployments, custom frontends, API integrations
- Pros: Minimal resources, no nginx overhead
- Example: Use with external frontend or API consumers
4. Multi-Backend Setup
- Best for: Load balancing, high availability
- Example:
services: backend-1: image: stirlingtools/stirling-pdf:unified environment: MODE: BACKEND backend-2: image: stirlingtools/stirling-pdf:unified environment: MODE: BACKEND frontend: image: stirlingtools/stirling-pdf:unified environment: MODE: FRONTEND VITE_API_BASE_URL: http://load-balancer:8080
Port Configuration
All modes use port 8080 by default:
- MODE=BOTH: Nginx listens on 8080, proxies to backend on internal 8081
- MODE=FRONTEND: Nginx listens on 8080
- MODE=BACKEND: Spring Boot listens on 8080
Expose port 8080 in all configurations:
ports:
- "8080:8080"
Health Checks
MODE=BOTH and MODE=BACKEND
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status || exit 1"]
interval: 30s
timeout: 10s
retries: 3
MODE=FRONTEND
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/ || exit 1"]
interval: 30s
timeout: 10s
retries: 3
Troubleshooting
Check logs
docker logs stirling-pdf-container
Look for the startup banner:
===================================
Stirling-PDF Unified Container
MODE: BOTH
===================================
Invalid MODE error
ERROR: Invalid MODE 'XYZ'. Must be BOTH, FRONTEND, or BACKEND
Fix: Set MODE to one of the three valid values.
Frontend can't connect to backend (MODE=FRONTEND)
Check:
VITE_API_BASE_URLpoints to correct backend URL- Backend container is running and accessible
- Network connectivity between containers
Backend not starting (MODE=BOTH or BACKEND)
Check:
- Sufficient memory allocated (4GB recommended)
- Java heap size (
JAVA_CUSTOM_OPTS) - Volume permissions for
/tmp/stirling-pdf
Migration Guide
From Separate Containers → MODE=BOTH
Before:
services:
frontend:
image: stirlingtools/stirling-pdf:frontend
ports: ["80:80"]
backend:
image: stirlingtools/stirling-pdf:backend
ports: ["8080:8080"]
After:
services:
stirling-pdf:
image: stirlingtools/stirling-pdf:unified
ports: ["8080:8080"]
environment:
MODE: BOTH
From Legacy → MODE=BACKEND
services:
stirling-pdf:
image: stirlingtools/stirling-pdf:latest
ports: ["8080:8080"]
Becomes:
services:
stirling-pdf:
image: stirlingtools/stirling-pdf:unified
ports: ["8080:8080"]
environment:
MODE: BACKEND
Performance Tuning
MODE=BOTH
environment:
JAVA_CUSTOM_OPTS: "-Xmx4g -XX:MaxRAMPercentage=75"
BACKEND_INTERNAL_PORT: 8081
deploy:
resources:
limits:
memory: 4G
reservations:
memory: 2G
MODE=FRONTEND (Lightweight)
deploy:
resources:
limits:
memory: 512M
reservations:
memory: 256M
MODE=BACKEND (Heavy Processing)
environment:
JAVA_CUSTOM_OPTS: "-Xmx8g"
deploy:
resources:
limits:
memory: 10G
reservations:
memory: 4G
Security Considerations
- MODE=BOTH: Backend not exposed externally (runs on internal port)
- MODE=BACKEND: API exposed directly - consider API authentication
- MODE=FRONTEND: Only serves static files - minimal attack surface
Enable security features:
environment:
DOCKER_ENABLE_SECURITY: "true"
SECURITY_ENABLELOGIN: "true"
Support
- Documentation: https://docs.stirlingpdf.com
- GitHub Issues: https://github.com/Stirling-Tools/Stirling-PDF/issues
- Docker Hub: https://hub.docker.com/r/stirlingtools/stirling-pdf
License
MIT License - See repository for full details