Blog entry
Deploy on render
This guide assumes you just finished the Wagtail tutorial, your .gitignore is set up, and you have not done anything related to deployment yet. It covers everything from first install to a live site, including Cloudinary for media storage.
Your current project structure
mysite/
โโโ .venv/
โโโ mysite/
โ โโโ base/
โ โโโ blog/
โ โโโ home/
โ โโโ media/
โ โโโ mysite/
โ โ โโโ settings/
โ โ โ โโโ __init__.py
โ โ โ โโโ base.py โ shared settings (INSTALLED_APPS, etc.)
โ โ โ โโโ dev.py โ local dev (SQLite, DEBUG=True, SECRET_KEY)
โ โ โ โโโ production.py โ production (we'll edit this)
โ โ โโโ static/
โ โ โโโ templates/
โ โ โโโ __init__.py
โ โ โโโ urls.py
โ โ โโโ wsgi.py
โ โโโ portfolio/
โ โโโ search/
โ โโโ .dockerignore
โ โโโ .gitignore
โ โโโ db.sqlite3
โ โโโ Dockerfile
โ โโโ manage.py
โ โโโ requirements.txt
โ โโโ README.md
Why Cloudinary?
Render's web services have an ephemeral filesystem โ any files written to disk (like uploaded images) are lost on every deploy or restart. So if you upload images through Wagtail's admin, they'd disappear next time Render rebuilds your app.
Cloudinary solves this by storing your media files (images, documents) on their cloud servers instead of on Render's disk. Your images are served via Cloudinary's CDN, which is also faster for your visitors.
The good news: you don't need to change any of your models, templates, or blocks. Your ForeignKey('wagtailimages.Image', ...), ImageBlock(), FieldPanel('image'), and {% image %} template tags all stay exactly the same. Cloudinary works at the storage layer โ it just changes where the file bytes get saved.