Quickstart: image scaling with Thumbor in 5 minutes#
What you will build#
In this tutorial you will run a Plone 6 site with Thumbor-based image scaling, all backed by a single PostgreSQL database. You will upload an image, see Plone redirect to a signed Thumbor URL, and verify that Thumbor scales the image on the fly.
By the end you will have a four-container stack (PostgreSQL, Plone, Thumbor,
nginx) where Plone never touches image bytes – every @@images request
becomes a 302 redirect to Thumbor.
Prerequisites#
Docker and Docker Compose v2+
A web browser
A terminal
About 2 GB free disk space (for Docker images)
Step 1: clone the repository#
git clone https://github.com/bluedynamics/plone-pgthumbor.git
cd plone-pgthumbor/tryout
All remaining commands assume you are inside the tryout/ directory.
This setup installs all packages from PyPI – no source checkout required.
Note
For development with local source installs, use the development/ directory
instead.
See Set up a development environment for details.
Step 2: start the stack#
docker compose up -d --build
The Thumbor service uses the pre-built image from GHCR
(ghcr.io/bluedynamics/zodb-pgjsonb-thumborblobloader), available for
linux/amd64 and linux/arm64.
Only the Plone service is built locally.
This starts four services:
Service |
Port |
Description |
|---|---|---|
postgres |
5434 |
PostgreSQL 17 with zodb-pgjsonb storage |
plone |
8080 |
Plone 6.2 backend (via nginx) |
thumbor |
8888 |
Thumbor 7 image processor (pre-built from GHCR) |
nginx |
8080 |
Reverse proxy (public entry point) |
Wait until all services are healthy:
docker compose ps
Plone may take 30–60 seconds on first start while it creates the Plone site
and installs the plone.pgthumbor:default and plone.pgcatalog:default
GenericSetup profiles.
Tip
Watch the Plone logs to see when startup is complete:
docker compose logs -f plone
Look for the line Listening on 0.0.0.0:8080.
Step 3: log in to Plone#
Open http://localhost:8080 in your browser.
Log in with the default credentials:
Username:
adminPassword:
admin
You should see the Plone site root.
Step 4: upload an image#
Click Add new… > Image in the toolbar. 2. Give it a title, for example “Test Image.” 3. Choose any JPEG or PNG file from your computer. 4. Click Save.
Plone displays the image on the content view.
Step 5: inspect the Thumbor URL#
Right-click the displayed image and choose Copy Image Address (or Open Image in New Tab).
The URL will look like this:
http://localhost:8080/thumbor/<hmac>/300x200/<zoid_hex>/<tid_hex>
Key observations:
The path starts with
/thumbor/– nginx routes this to the Thumbor service.The
<hmac>segment is the HMAC-SHA1 signature (generated by Plone using the sharedPGTHUMBOR_SECURITY_KEY).300x200(or similar) is the target size Plone requested.<zoid_hex>/<tid_hex>identifies the blob in PostgreSQL.
Plone itself returned a 302 redirect to this URL.
It never read the blob
data – Thumbor fetches it directly from the blob_state table in PostgreSQL.
Step 6: verify scaling works#
Open a new browser tab and paste the Thumbor URL. You should see the scaled image.
Try modifying the size in the URL manually.
For example, change 300x200 to
100x100 – Thumbor will return a 403 Forbidden because the new URL has an
invalid HMAC signature.
This proves that the security key prevents arbitrary
transformations.
Tip
The example stack sets ALLOW_UNSAFE_URL=True in the Thumbor container
environment.
In production this must be False – all URLs must be signed.
You can test unsigned URLs by prefixing the path with /unsafe/ instead of
an HMAC, but only while unsafe mode is enabled.
Step 7: clean up#
docker compose down -v
This removes all containers and the PostgreSQL data volume.
Omit -v if you
want to keep the data for next time.
What you learned#
plone.pgthumbor replaces Plone’s
@@imagesview with a 302 redirect to ThumborImage bytes never pass through the Plone process – Thumbor reads them directly from PostgreSQL via zodb-pgjsonb-thumborblobloader
nginx serves as a reverse proxy, routing
/thumbor/to the Thumbor service and everything else to Plone (with VirtualHostMonster rewriting)HMAC-signed URLs prevent unauthorized image transformations
Next steps#
Install plone.pgthumbor to install both packages in your own environment
Configure Thumbor for plone.pgthumbor for the full list of Thumbor settings
Configure Plone settings for Plone-side environment variables and registry settings
Production deployment checklist for a production deployment checklist