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