Stirling-PDF/docker/embedded/compose/README-remote-uno.md
Anthony Stirling 3e061516a5
Libre threads (#5303)
# 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.
2026-01-15 19:14:45 +00:00

6.5 KiB

Stirling-PDF with Remote UNO Servers

This docker-compose configuration demonstrates running Stirling-PDF with separate UNO server containers for LibreOffice document conversion, enabling horizontal scaling and better resource isolation.

Architecture

┌─────────────────────┐
│   Stirling-PDF      │
│   (Main App)        │
│                     │
│ Uses BlockingQueue  │
│ pool to distribute  │
│ load across servers │
└──────┬──────┬───────┘
       │      │
       │      │ Remote endpoints
       │      │ (hostLocation: remote)
       │      │
   ┌───▼──┐ ┌─▼────┐
   │ UNO  │ │ UNO  │
   │ #1   │ │ #2   │
   │:2002 │ │:2002 │
   └──────┘ └──────┘

Key Features Demonstrated

1. Remote UNO Server Configuration

  • hostLocation: "remote" - Required for cross-container communication
  • BlockingQueue pool - Optimal endpoint selection under load
  • Health checks - Each UNO server has unoping health check

2. Environment Variable Configuration

PROCESS_EXECUTOR_AUTO_UNO_SERVER: "false"  # Disable local servers

# Define remote endpoints (Spring Boot list syntax)
PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_0_HOST: "unoserver1"
PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_0_PORT: "2002"
PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_0_HOST_LOCATION: "remote"  # Critical!
PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_0_PROTOCOL: "http"

PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_1_HOST: "unoserver2"
PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_1_PORT: "2002"
PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_1_HOST_LOCATION: "remote"
PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_1_PROTOCOL: "http"

3. Session Limit

PROCESS_EXECUTOR_SESSION_LIMIT_LIBRE_OFFICE_SESSION_LIMIT: "2"

Should match endpoint count for optimal concurrency.

Usage

Start the Stack

docker compose -f docker-compose-latest-security-remote-uno.yml up -d

Monitor Logs

# Watch all services
docker compose -f docker-compose-latest-security-remote-uno.yml logs -f

# Watch just UNO servers
docker compose -f docker-compose-latest-security-remote-uno.yml logs -f unoserver1 unoserver2

# Watch main app
docker compose -f docker-compose-latest-security-remote-uno.yml logs -f stirling-pdf

Health Check Status

docker compose -f docker-compose-latest-security-remote-uno.yml ps

Should show all services healthy:

NAME                           STATUS
Stirling-PDF-Security-Remote-UNO   Up (healthy)
UNO-Server-1                       Up (healthy)
UNO-Server-2                       Up (healthy)

Test Conversion Load Distribution

Upload multiple documents for conversion and watch the logs - you'll see requests distributed across both UNO servers via the BlockingQueue pool.

Scaling UNO Servers

Add More Servers

To add a 3rd UNO server:

  1. Add service to compose file:
  unoserver3:
    container_name: UNO-Server-3
    image: ghcr.io/unoconv/unoserver-docker:0.4.4
    # ... same config as unoserver1/2
  1. Add environment variables to stirling-pdf service:
      PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_2_HOST: "unoserver3"
      PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_2_PORT: "2002"
      PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_2_HOST_LOCATION: "remote"
      PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_2_PROTOCOL: "http"
      PROCESS_EXECUTOR_SESSION_LIMIT_LIBRE_OFFICE_SESSION_LIMIT: "3"  # Update!
  1. Add to depends_on:
    depends_on:
      unoserver1:
        condition: service_healthy
      unoserver2:
        condition: service_healthy
      unoserver3:
        condition: service_healthy

Scale with Docker Compose (Alternative)

docker compose -f docker-compose-latest-security-remote-uno.yml up -d --scale unoserver1=3

Note: This requires removing container_name and hardcoded ports.

Troubleshooting

"Connection refused" errors

  • Cause: hostLocation: "auto" or missing
  • Fix: Set HOSTLOCATION: "remote" for all endpoints

Conversions using only one server

  • Cause: Session limit too low or not matching endpoint count
  • Fix: Set PROCESS_EXECUTOR_SESSION_LIMIT_LIBRE_OFFICE_SESSION_LIMIT to match endpoint count

UNO server not starting

  • Check: docker compose logs unoserver1
  • Common: LibreOffice profile corruption
  • Fix: docker compose down -v (removes volumes)

Comparison: Local vs Remote UNO Servers

Local (Auto) Mode

PROCESS_EXECUTOR_AUTO_UNO_SERVER: "true"
PROCESS_EXECUTOR_SESSION_LIMIT_LIBRE_OFFICE_SESSION_LIMIT: "2"
# Creates 2 servers on 127.0.0.1:2003, 127.0.0.1:2005 inside container (Stirling-PDF's own servers)
  • Simpler configuration
  • Lower latency
  • All in one container (resource competition)
  • Can't scale independently

Remote Mode (This File)

PROCESS_EXECUTOR_AUTO_UNO_SERVER: "false"
# Define external endpoints with hostLocation: "remote"
  • Resource isolation (separate containers)
  • Independent scaling
  • Better resilience (restart one without affecting others)
  • Slightly higher network overhead
  • More complex configuration

Advanced Configuration

HTTPS UNO Servers

If your UNO servers use HTTPS (e.g., behind a reverse proxy):

PROCESS_EXECUTOR_UNOSERVERENDPOINTS_0_PROTOCOL: "https"

Custom Health Check Interval

  unoserver1:
    healthcheck:
      interval: 5s    # Check more frequently
      timeout: 3s
      retries: 10
      start_period: 60s  # Give more startup time

Debug Mode

To see detailed endpoint selection logs:

environment:
  LOGGING_LEVEL_STIRLING_SOFTWARE_COMMON_UTIL_PROCESSEXECUTOR: DEBUG

What This Demonstrates

This configuration showcases all the improvements from the PR reviews:

  1. Remote endpoint support (hostLocation: "remote")
  2. BlockingQueue pool (optimal endpoint distribution)
  3. Idempotent lease close (thread-safe)
  4. Robust health checks (unoping → TCP → PID fallbacks)
  5. Proper validation (hostLocation/protocol normalized)
  6. Session limit warnings (logs mismatch if misconfigured)

Performance Expectations

With 2 UNO servers, you can expect:

  • 2x concurrent conversions vs single server
  • ~50% reduction in queue wait time under load
  • Better resilience: One server failure = 50% capacity, not 0%

Tested with 100GB+ PDFs - BlockingQueue ensures no endpoint starvation.