Site ↗
Documentation sections
Operations · 0.8.1

Image storage: disk directory or S3

Where images live, how to configure Local or S3, and why files must move together with a database dump.

On this page

Images are stored separately from PostgreSQL. The database contains asset records, references, and alt text; a gallery contains ordered references. Direct size URLs from the external API do not replace the files themselves.

Local: a disk directory

The default dev path is ~/.local/share/example_project/media, where example_project is the technical project name. Set another absolute path with MEDIA_ROOT. Each database needs its own directory.

For prod-local and servers, set the path in the Deployment environments profile under Image storage → Media directory; it is usually <root>/data/media. The directory is mounted into the backend and must survive container replacement. After manual copying, files must be accessible to UID/GID 10001:10001.

This is not a cache: deleting the directory destroys image files. When transferring, preserve the database and the entire directory, including prepared sizes.

S3: prepare the project and settings

  1. Select S3 for images in Generator UI and run Generate. Environment variables alone are insufficient if the project uses the Local adapter.
  2. Create a private bucket and a separate prefix for the environment.
  3. Open the profile in Deployment → Deployment environments. Under Image storage, enter your storage endpoint, region, bucket, and prefix. Save and run Generate. Parameters go into the generated profile; manual JSON copying is unnecessary.

For example: endpoint https://s3.example.com, region us-east-1, bucket project-media, prefix production. These are placeholders: your S3 provider supplies the actual address, region, and bucket. Use a separate prefix for each environment. Do not enter passwords in the UI profile.

Create a separate private file outside the repository and export DEPLOY_SECRETS_FILE with its absolute path before provision. Source reads the file on the VPS; Archive/Registry reads it on your computer. Contents:

{
  "media_access_key": "REPLACE_ME",
  "media_secret_key": "REPLACE_ME"
}

For temporary keys, add media_session_token. During first provisioning, this bundle may also contain registry/backup credentials — see server startup. Later rotation needs a separate file containing only keys of the selected kind.

S3 in prod-local and dev

Initial prod-local provisioning obtains keys from files:

export MEDIA_S3_ACCESS_KEY_FILE=/absolute/private/media-access-key
export MEDIA_S3_SECRET_KEY_FILE=/absolute/private/media-secret-key
# Если провайдер использует временный token:
# export MEDIA_S3_SESSION_TOKEN_FILE=/absolute/private/media-session-token

bash ./deploy/control provision --env local

Each file contains one value accessible only to the appropriate user. For make dev, separately set MEDIA_S3_ENDPOINT, MEDIA_S3_REGION, MEDIA_S3_BUCKET, MEDIA_S3_PREFIX, and key file paths: dev does not read deployment JSON. Do not share a prefix between dev and production.

Update sizes or clean up old uploads

Generate does not recreate sizes for existing images. Open the record in the admin interface, click Update sizes, and save. The previous version remains attached until the new one is saved successfully.

To clean up unused uploads and detached images after the waiting period, run in the active backend:

docker exec ИМЯ_КОНТЕЙНЕРА_BACKEND media-cleanup -limit 100

One run processes at most 100 records. Repeat for larger queues. Do not run cleanup during backup, transfer, or restore.

Move files elsewhere

If the database already contains images, the backend remembers their storage. Simply changing a path or bucket produces media storage cannot change while assets exist: transfer the corresponding files first, then update the binding.

For Local → Local, use data transfer; standard restore performs its own changes automatically. There is currently no universal Local ↔ S3 command: that requires a separate migration of objects and references. Keep backups separate from working media so losing media does not destroy the backup too.