Optimizing Stirling-PDF: Persistent Storage and Upload Limits
Master Stirling-PDF deployment by configuring persistent storage for data safety and tuning reverse proxy settings to process large document uploads.
Stirling-PDF has emerged as a premier self-hosted solution for document manipulation, offering a feature-rich interface for everything from merging and splitting PDFs to advanced OCR and image conversion. However, transitioning from a quick local test to a reliable service requires addressing the realities of containerized infrastructure. Two of the most common friction points for administrators are data volatility and restrictive request limits. When you deploy Stirling-PDF via Docker, you are working within an ephemeral environment. If you do not explicitly configure persistence, your processed documents, custom configurations, and logs will be wiped clean every time the container restarts or updates. Furthermore, the default configurations of many web servers and reverse proxies are set to reject large file uploads, which can lead to frustrating "413 Request Entity Too Large" errors when you attempt to process high-resolution scans or multi-hundred-page documents. This guide provides a deep dive into configuring robust persistent storage and tuning your infrastructure to support high-volume, production-ready PDF processing.
The Architecture of Containerized Storage
To understand why persistence is a challenge, we must look at how Docker manages the filesystem. A Docker container consists of a series of read-only image layers, topped by a thin, writable layer. Any file created, modified, or deleted inside the container during its runtime exists only in that writable layer. When the container is deleted—which happens whenever you run docker-compose down or pull a new image version—that layer is destroyed, and the data is lost forever.
Stirling-PDF relies on several internal directories to function correctly. These include /configs for user-defined settings, /logs for diagnostic information, /customFiles for assets like fonts or templates, and sometimes /usr/share/tessdata if you are utilizing advanced OCR features. By default, these paths are internal to the container. To make them persistent, we use Docker volumes or bind mounts. A bind mount maps a specific directory on your host machine's filesystem to a path inside the container. This creates a bridge: any file written to that path by the application is physically stored on your host's disk, surviving any container lifecycle events.
Implementing Persistent Storage via Docker Compose
Docker Compose is the industry standard for managing multi-container applications because it allows you to codify your infrastructure. Instead of manually typing long docker run commands, you define your desired state in a docker-compose.yml file. This ensures that your storage configuration is reproducible and version-controlled.
Below is a production-ready docker-compose.yml configuration. Note the use of explicit volume mappings that target the specific directories Stirling-PDF requires for state management.
version: '3.8'
services:
stirling-pdf:
image: frooodle/stirling-pdf:latest
container_name: stirling-pdf
ports:
- "8080:8080"
volumes:
- ./data/configs:/configs
- ./data/logs:/logs
- ./data/customFiles:/customFiles
- ./data/tessdata:/usr/share/tessdata
environment:
- DOCKER_ENABLE_SECURITY=false
- INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false
restart: unless-stopped
Why These Specific Mappings Matter
- /configs: This directory holds your application-level settings. If you change your UI theme, security policies, or API keys, these are saved here. Without this mount, you would have to re-configure the application every time you update the image.
- /logs: Essential for troubleshooting. If the application crashes or fails to process a document, the logs are your primary source of truth. By mapping this to the host, you can use standard Linux tools like
tail -forgrepto monitor errors in real-time without entering the container. - /customFiles: This is where you might store custom fonts or branding assets. If your workflow requires specific corporate fonts for PDF generation, this mount ensures they are always available to the application.
- /usr/share/tessdata: This is specific to Tesseract OCR. If you perform OCR, the application needs access to language data files. Mapping this allows you to add custom language packs (e.g., Japanese, Cyrillic) without modifying the image itself.
Managing Permissions and Ownership
One common pitfall when using bind mounts is permission conflicts. Because the container process often runs as a specific user (usually UID 1000 or root), the files created on the host might have ownership that prevents your host-level processes from reading them, or conversely, the container might lack write access to a folder you created on the host.
Before launching the container, ensure your host directories are prepared:
mkdir -p ./data/configs ./data/logs ./data/customFiles ./data/tessdata
chmod -R 755 ./data
If you encounter "Permission Denied" errors in your logs, verify the UID/GID of the user inside the container. You can check this by running docker exec stirling-pdf id. If the container is running as a non-root user, you may need to chown your host directories to match that user's ID to ensure seamless read/write access.
Overcoming File Upload Limitations
Even with perfect storage, you will likely encounter a "413 Request Entity Too Large" error when attempting to upload a 50MB or 100MB PDF. This error is not a bug in Stirling-PDF; it is a security feature of your web server or reverse proxy. Most web servers (like Nginx, Apache, or Traefik) have a default upload limit—often as low as 1MB or 2MB—to prevent Denial of Service (DoS) attacks where a malicious actor floods the server with massive files.
If you are using Nginx as a reverse proxy to expose Stirling-PDF to the internet, you must explicitly raise this limit. The directive responsible for this is client_max_body_size.
Configuring Nginx for Large Payloads
Edit your Nginx server block configuration. This is usually located in /etc/nginx/sites-available/your-domain.conf or a similar path depending on your OS distribution.
server {
listen 80;
server_name pdf.yourdomain.com;
location / {
proxy_pass http://localhost:8080;
# Increase upload limit to 200MB
client_max_body_size 200M;
# Standard proxy headers
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
After modifying the file, always test the configuration syntax before reloading the service:
sudo nginx -t
# If successful, reload
sudo systemctl reload nginx
If you are using other proxies like Traefik or Caddy, the configuration will differ. In Traefik, you would use a middleware with maxRequestBodySize. In Caddy, you would use the request_body directive. Always consult your proxy's documentation for the specific syntax, but the underlying principle remains: you must explicitly permit larger request bodies at the edge of your network.
Scaling and Maintenance Considerations
As your usage grows, your persistent storage directory will inevitably fill up. PDF processing is resource-intensive, and temporary files created during conversion can accumulate if the application does not prune them correctly.
Implementing a Cleanup Strategy
To keep your storage healthy, implement a simple cron job on the host machine. This is more reliable than relying on the application to clean up after itself, especially if a process crashes mid-task.
Create a shell script cleanup_pdfs.sh:
#!/bin/bash
# Delete files older than 7 days in the logs and temp directories
find /path/to/your/data/logs -type f -mtime +7 -delete
echo "Cleanup complete at $(date)" >> /var/log/stirling-cleanup.log
Add this to your crontab (crontab -e) to run daily:
0 3 * * * /usr/local/bin/cleanup_pdfs.sh
This proactive maintenance ensures that your disk space remains available for active tasks rather than being consumed by stale logs or orphaned temporary files.
Diagnostic Workflow for Storage Issues
If you suspect that your storage is not working as expected, follow this diagnostic checklist:
- Inspect the Mounts: Run
docker inspect stirling-pdf. Look for theMountssection in the JSON output. Verify that theSource(host path) andDestination(container path) match yourdocker-compose.ymlconfiguration exactly. - Verify Write Access: Enter the container and attempt to create a dummy file:
docker exec -it stirling-pdf touch /logs/test.txt. If this fails, you have a permission issue on the host folder. - Check Disk Space: Run
df -hon the host. If the partition containing your data directory is full, the container will be unable to write new files, leading to cryptic "IO Error" messages in the application UI. - Check Proxy Logs: If uploads fail, check your Nginx error logs (usually
/var/log/nginx/error.log). If you see "client intended to send too large body," yourclient_max_body_sizesetting is either ignored or not applied to the correct location block.
Security and Operational Trade-offs
While persistent storage is necessary, it introduces a security consideration: the data on your host is now accessible to any process with read access to those directories. If you are storing sensitive documents, ensure that the host directory permissions are restricted (e.g., chmod 700).
Furthermore, consider the failure domain. If your host machine experiences a disk failure, your persistent storage is lost. For production-grade resilience, you should implement a backup strategy for your host directory. Tools like rsync or automated cloud backups (using S3 or B2) can replicate your ./data directory to an off-site location. Never assume that local persistence is a substitute for a robust backup strategy; it is merely a way to survive container restarts, not hardware failure.
By following these steps, you transform a fragile containerized instance into a stable, high-performance document processing engine. You have decoupled the application from its ephemeral lifecycle, enabled the processing of large files, and established a foundation for maintenance and monitoring. These practices are the hallmarks of professional-grade self-hosting, ensuring that your tools serve you reliably over the long term.
Frequently Asked Questions
Why do my files disappear when I restart the Stirling-PDF container?
Files disappear because the container filesystem is ephemeral by default, meaning any changes made inside the container are lost when it is destroyed. You must use Docker volumes or bind mounts in your docker-compose.yml to map a host directory to the container's internal storage paths to ensure data persists across restarts.
How do I know if my Nginx configuration is blocking large file uploads?
If you receive a 413 Request Entity Too Large error in your browser when attempting an upload, your reverse proxy is actively rejecting the request. You must increase the clientmaxbody_size directive in your Nginx configuration block to match or exceed the size of the files you intend to process.
Is it safe to mount the entire Stirling-PDF directory to the host?
It is generally considered a bad practice to mount the entire root directory of a container because it can lead to permission conflicts and unexpected behavior if the host and container operating systems differ. It is much safer and more maintainable to mount only the specific subdirectories required for data, such as logs, configs, and custom assets.
Can I use a cloud storage bucket instead of local disk storage?
While you can use tools like s3fs to mount cloud storage as a local directory, this often introduces significant latency that can degrade the performance of PDF processing tasks. For the best balance of speed and reliability in a self-hosted environment, local SSD storage remains the recommended approach for your primary data volume.