Configuration for hosting media files on S3 with Gramps Web

Hi,

I would like to set up S3 (Simple Storage Service on Amazon Web Services) in my Gramps Web instance. I am using the docker setup on a Raspberry Pi 3B.
After my configuration, I would expect that when I add a media file in the Gramps Web interface, it appears in the S3 bucket. However, it does not, but instead appears in the local media folder.
Can you please help me to correctly set up S3?


I followed the documentation on “Hosting media files on S3”.
The documentation says

When using Docker Compose, the easiest option is to add all environment variables to the env block

I understand this as adding the variables to the environment block in the grampsweb part of docker compose, i.e., the beginning of my “docker-compose.yml” is

services:
  grampsweb: &grampsweb
    container_name: grampsweb
    image: [...]grampsweb:latest # removed link as I can only include 2 links
    environment: &grampsweb-env
      GRAMPSWEB_TREE: "Gramps Web"  # will create a new tree if not exists
      GUNICORN_NUM_WORKERS: 2 # only use 2 cores
      VIRTUAL_PORT: "5000"
      VIRTUAL_HOST: <my-domain>
      LETSENCRYPT_HOST: <my-domain>
      LETSENCRYPT_EMAIL: <my-email>
      GRAMPSWEB_CELERY_CONFIG__broker_url:  # removed link as I can only include 2 links
      GRAMPSWEB_CELERY_CONFIG__result_backend:  # removed link as I can only include 2 links
      GRAMPSWEB_RATELIMIT_STORAGE_URI: # removed link as I can only include 2 links
      # Amazon
      AWS_ACCESS_KEY_ID: <my-access-key>
      AWS_SECRET_ACCESS_KEY: <my-secret-key>
      MEDIA_BASE_DIR: <s3-and-my-bucket-name>
      AWS_DEFAULT_REGION: eu-central-1
    volumes: # removed the others, are these considered links?
      - /home/pi/gramps_media:/app/media

Things I was unsure about

  • There is no env block in “docker-compose.yml”. Have I put the variables at the right spot?
  • The documentation on configuration says to put variables such as MEDIA_BASE_DIR either in the configuration file, or add environment variables. I do the latter, but the instructions on how to setup S3 do not prepend GRAMPSWEB to the environment variables

Using S3 is new to me. I have tried to make sure my configuration is correct by testing from the command line with s3cmd:

s3cmd --access_key=<my-access-key> --secret_key=<my-secret-key --region=eu-central-1 put file.png <s3-and-my-bucket-name>

The file was indeed uploaded to the desired bucket.

My system information is:

Gramps 5.2.2
Gramps Web API 2.4.2
Gramps Web Frontend 24.8.0
Gramps QL 0.3.0
locale: en
multi-tree: false
task queue: true

Please change MEDIA_BASE_DIR to GRAMPSWEB_MEDIA_BASE_DIR.

1 Like

I changed to GRAMPSWEB_MEDIA_BASE_DIR, restarted with docker compose restart, then uploaded a media file.
The file still does not show up in the S3 bucket.

Can you share more of your configuration? Something must be wrong, likely a typo somewhere. And please also look at the logs.

David,

thanks for helping me out. The information you required follows. I am not sure what to make of the logs on my own, nothing really catches my eye.

Best, Patrick

Configuration

Here is the docker-compose.yml. I highlighted the results of a diff to the original file from the setup instructions.

services:
  grampsweb: &grampsweb
    container_name: grampsweb
    image: ghcr.io/gramps-project/grampsweb:latest
    restart: always
    environment: &grampsweb-env
      GRAMPSWEB_TREE: "Gramps Web"  # will create a new tree if not exists
      VIRTUAL_PORT: "5000"
-     VIRTUAL_HOST: ...  # e.g. gramps.mydomain.com
+     VIRTUAL_HOST: <my-domain>  # e.g. gramps.mydomain.com
-     LETSENCRYPT_HOST: ...   # e.g. gramps.mydomain.com
+     LETSENCRYPT_HOST: <my-domain>   # e.g. gramps.mydomain.com
-     LETSENCRYPT_EMAIL: ...  # your email
+     LETSENCRYPT_EMAIL: <my-mail>  # your email
      GRAMPSWEB_CELERY_CONFIG__broker_url: "redis://grampsweb_redis:6379/0"
      GRAMPSWEB_CELERY_CONFIG__result_backend: "redis://grampsweb_redis:6379/0"
      GRAMPSWEB_RATELIMIT_STORAGE_URI: redis://grampsweb_redis:6379/1
+     # Amazon
+     AWS_ACCESS_KEY_ID: <my-access-key>
+     AWS_SECRET_ACCESS_KEY: <my-secret-key>
+     # General
+     GRAMPSWEB_MEDIA_BASE_DIR: s3://scheffe-gramps
+     # MEDIA_BASE_DIR: s3://scheffe-gramps
+     AWS_DEFAULT_REGION: eu-central-1
    volumes:
      - gramps_users:/app/users
      - gramps_index:/app/indexdir
      - gramps_thumb_cache:/app/thumbnail_cache
      - gramps_cache:/app/cache
      - gramps_secret:/app/secret
      - gramps_db:/root/.gramps/grampsdb
-     - gramps_media:/app/media
+     - /home/pi/gramps_media:/app/media
      - gramps_tmp:/tmp
    networks:
      - proxy-tier
      - default

  grampsweb_celery:
    <<: *grampsweb  # YAML merge key copying the entire grampsweb service config
    container_name: grampsweb_celery
    depends_on:
      - grampsweb_redis
    environment:
      <<: *grampsweb-env  # YAML merge key copying the grampsweb environment config
      # overriding let's encrypt variables since celery is not exposed
      VIRTUAL_PORT: ""
      VIRTUAL_HOST: ""
      LETSENCRYPT_HOST: ""
      LETSENCRYPT_EMAIL: ""
    command: celery -A gramps_webapi.celery worker --loglevel=INFO

  grampsweb_redis:
    image: docker.io/library/redis:7.2.4-alpine
    container_name: grampsweb_redis
    restart: always

  proxy:
    image: docker.io/nginxproxy/nginx-proxy
    container_name: nginx-proxy
    restart: always
    ports:
      - 80:80
      - 443:443
    environment:
      ENABLE_IPV6: "true"
    volumes:
      - ./nginx_proxy.conf:/etc/nginx/conf.d/my_proxy.conf:ro
      - conf:/etc/nginx/conf.d
      - dhparam:/etc/nginx/dhparam
      - certs:/etc/nginx/certs:ro
      - vhost.d:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
      - /var/run/docker.sock:/tmp/docker.sock:ro
    networks:
      - proxy-tier

  acme-companion:
    image: docker.io/nginxproxy/acme-companion
    container_name: nginx-proxy-acme
    restart: always
    environment:
      NGINX_PROXY_CONTAINER: nginx-proxy
    volumes:
      - certs:/etc/nginx/certs:rw
      - vhost.d:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
      - acme:/etc/acme.sh
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - proxy-tier
    depends_on:
      - proxy

volumes:
  acme:
  certs:
  conf:
  dhparam:
  vhost.d:
  html:
  gramps_users:
  gramps_index:
  gramps_thumb_cache:
  gramps_cache:
  gramps_secret:
  gramps_db:
  gramps_media:
  gramps_tmp:

networks:
  proxy-tier:

Logs

To generate hopefully useful logs, I have done the following

  1. restart the docker containers (docker compose restart)
  2. upload a test media file
  3. look at recent logs with docker compose logs $SERVICE --since=60m, where $SERVICE are grampsweb, grampsweb_celery, grampsweb_redis

grampsweb

grampsweb  | /usr/local/lib/python3.11/dist-packages/gramps/plugins/tool/check.py:51: PyGIWarning: Gtk was imported without specifying a version first. Use gi.require_version('Gtk', '3.0') before import to ensure that the right version gets loaded.
grampsweb  |   from gi.repository import Gtk
grampsweb  | 
grampsweb  | (__main__.py:9): Gtk-CRITICAL **: 14:11:33.471: gtk_icon_theme_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed
grampsweb  | INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
grampsweb  | INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
grampsweb  | [2024-10-01 14:11:54 +0000] [13] [INFO] Starting gunicorn 22.0.0
grampsweb  | [2024-10-01 14:11:54 +0000] [13] [INFO] Listening at: http://0.0.0.0:5000 (13)
grampsweb  | [2024-10-01 14:11:54 +0000] [13] [INFO] Using worker: sync
grampsweb  | [2024-10-01 14:11:54 +0000] [14] [INFO] Booting worker with pid: 14
grampsweb  | [2024-10-01 14:11:54 +0000] [15] [INFO] Booting worker with pid: 15
grampsweb  | /usr/local/lib/python3.11/dist-packages/gramps/plugins/tool/check.py:51: PyGIWarning: Gtk was imported without specifying a version first. Use gi.require_version('Gtk', '3.0') before import to ensure that the right version gets loaded.
grampsweb  |   from gi.repository import Gtk
grampsweb  | /usr/local/lib/python3.11/dist-packages/gramps/plugins/tool/check.py:51: PyGIWarning: Gtk was imported without specifying a version first. Use gi.require_version('Gtk', '3.0') before import to ensure that the right version gets loaded.
grampsweb  |   from gi.repository import Gtk
grampsweb  | 
grampsweb  | (gunicorn:14): Gtk-CRITICAL **: 14:12:12.601: gtk_icon_theme_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed
grampsweb  | 
grampsweb  | (gunicorn:15): Gtk-CRITICAL **: 14:12:12.601: gtk_icon_theme_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed

grampsweb_celery

grampsweb_celery  | 
grampsweb_celery  | worker: Warm shutdown (MainProcess)
grampsweb_celery  | /usr/local/lib/python3.11/dist-packages/gramps/plugins/tool/check.py:51: PyGIWarning: Gtk was imported without specifying a version first. Use gi.require_version('Gtk', '3.0') before import to ensure that the right version gets loaded.
grampsweb_celery  |   from gi.repository import Gtk
grampsweb_celery  | 
grampsweb_celery  | (__main__.py:9): Gtk-CRITICAL **: 14:11:33.471: gtk_icon_theme_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed
grampsweb_celery  | INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
grampsweb_celery  | INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
grampsweb_celery  | /usr/local/lib/python3.11/dist-packages/gramps/plugins/tool/check.py:51: PyGIWarning: Gtk was imported without specifying a version first. Use gi.require_version('Gtk', '3.0') before import to ensure that the right version gets loaded.
grampsweb_celery  |   from gi.repository import Gtk
grampsweb_celery  | 
grampsweb_celery  | (celery:1): Gtk-CRITICAL **: 14:12:14.108: gtk_icon_theme_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed
grampsweb_celery  | /usr/local/lib/python3.11/dist-packages/celery/platforms.py:829: SecurityWarning: You're running the worker with superuser privileges: this is
grampsweb_celery  | absolutely not recommended!
grampsweb_celery  | 
grampsweb_celery  | Please specify a different user using the --uid option.
grampsweb_celery  | 
grampsweb_celery  | User information: uid=0 euid=0 gid=0 egid=0
grampsweb_celery  | 
grampsweb_celery  |   warnings.warn(SecurityWarning(ROOT_DISCOURAGED.format(
grampsweb_celery  |  
grampsweb_celery  |  -------------- celery@ec0cb81feccd v5.4.0 (opalescent)
grampsweb_celery  | --- ***** ----- 
grampsweb_celery  | -- ******* ---- Linux-6.1.21-v7+-armv7l-with-glibc2.36 2024-10-01 14:12:21
grampsweb_celery  | - *** --- * --- 
grampsweb_celery  | - ** ---------- [config]
grampsweb_celery  | - ** ---------- .> app:         default:0x6b97c730 (.default.Loader)
grampsweb_celery  | - ** ---------- .> transport:   redis://grampsweb_redis:6379/0
grampsweb_celery  | - ** ---------- .> results:     redis://grampsweb_redis:6379/0
grampsweb_celery  | - *** --- * --- .> concurrency: 4 (prefork)
grampsweb_celery  | -- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
grampsweb_celery  | --- ***** ----- 
grampsweb_celery  |  -------------- [queues]
grampsweb_celery  |                 .> celery           exchange=celery(direct) key=celery
grampsweb_celery  |                 
grampsweb_celery  | 
grampsweb_celery  | [tasks]
grampsweb_celery  |   . gramps_webapi.api.tasks.check_repair_database
grampsweb_celery  |   . gramps_webapi.api.tasks.delete_objects
grampsweb_celery  |   . gramps_webapi.api.tasks.export_db
grampsweb_celery  |   . gramps_webapi.api.tasks.export_media
grampsweb_celery  |   . gramps_webapi.api.tasks.generate_report
grampsweb_celery  |   . gramps_webapi.api.tasks.import_file
grampsweb_celery  |   . gramps_webapi.api.tasks.import_media_archive
grampsweb_celery  |   . gramps_webapi.api.tasks.media_ocr
grampsweb_celery  |   . gramps_webapi.api.tasks.search_reindex_full
grampsweb_celery  |   . gramps_webapi.api.tasks.search_reindex_incremental
grampsweb_celery  |   . gramps_webapi.api.tasks.send_email_confirm_email
grampsweb_celery  |   . gramps_webapi.api.tasks.send_email_new_user
grampsweb_celery  |   . gramps_webapi.api.tasks.send_email_reset_password
grampsweb_celery  |   . gramps_webapi.api.tasks.upgrade_database_schema
grampsweb_celery  | 
grampsweb_celery  | [2024-10-01 14:12:23,788: WARNING/MainProcess] /usr/local/lib/python3.11/dist-packages/celery/worker/consumer/consumer.py:508: CPendingDeprecationWarning: The broker_connection_retry configuration setting will no longer determine
grampsweb_celery  | whether broker connection retries are made during startup in Celery 6.0 and above.
grampsweb_celery  | If you wish to retain the existing behavior for retrying connections on startup,
grampsweb_celery  | you should set broker_connection_retry_on_startup to True.
grampsweb_celery  |   warnings.warn(
grampsweb_celery  | 
grampsweb_celery  | [2024-10-01 14:12:23,911: INFO/MainProcess] Connected to redis://grampsweb_redis:6379/0
grampsweb_celery  | [2024-10-01 14:12:23,915: WARNING/MainProcess] /usr/local/lib/python3.11/dist-packages/celery/worker/consumer/consumer.py:508: CPendingDeprecationWarning: The broker_connection_retry configuration setting will no longer determine
grampsweb_celery  | whether broker connection retries are made during startup in Celery 6.0 and above.
grampsweb_celery  | If you wish to retain the existing behavior for retrying connections on startup,
grampsweb_celery  | you should set broker_connection_retry_on_startup to True.
grampsweb_celery  |   warnings.warn(
grampsweb_celery  | 
grampsweb_celery  | [2024-10-01 14:12:23,948: INFO/MainProcess] mingle: searching for neighbors
grampsweb_celery  | [2024-10-01 14:12:25,059: INFO/MainProcess] mingle: all alone
grampsweb_celery  | [2024-10-01 14:12:25,161: INFO/MainProcess] celery@ec0cb81feccd ready.

grampsweb_redis

grampsweb_redis  | 1:signal-handler (1727791846) Received SIGTERM scheduling shutdown...
grampsweb_redis  | 1:M 01 Oct 2024 14:10:46.501 * User requested shutdown...
grampsweb_redis  | 1:M 01 Oct 2024 14:10:46.527 * Saving the final RDB snapshot before exiting.
grampsweb_redis  | 1:M 01 Oct 2024 14:10:47.300 * DB saved on disk
grampsweb_redis  | 1:M 01 Oct 2024 14:10:47.309 # Redis is now ready to exit, bye bye...
grampsweb_redis  | 1:C 01 Oct 2024 14:11:02.798 # WARNING Memory overcommit must be enabled! Without it, a background save or replication may fail under low memory condition. Being disabled, it can also cause failures without low memory condition, see https://github.com/jemalloc/jemalloc/issues/1328. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
grampsweb_redis  | 1:C 01 Oct 2024 14:11:02.799 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
grampsweb_redis  | 1:C 01 Oct 2024 14:11:02.799 * Redis version=7.2.4, bits=32, commit=00000000, modified=0, pid=1, just started
grampsweb_redis  | 1:C 01 Oct 2024 14:11:02.799 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
grampsweb_redis  | 1:M 01 Oct 2024 14:11:02.806 * monotonic clock: POSIX clock_gettime
grampsweb_redis  | 1:M 01 Oct 2024 14:11:02.806 # Warning: 32 bit instance detected but no memory limit set. Setting 3 GB maxmemory limit with 'noeviction' policy now.
grampsweb_redis  | 1:M 01 Oct 2024 14:11:02.822 * Running mode=standalone, port=6379.
grampsweb_redis  | 1:M 01 Oct 2024 14:11:02.824 * Server initialized
grampsweb_redis  | 1:M 01 Oct 2024 14:11:02.829 * Loading RDB produced by version 7.2.4
grampsweb_redis  | 1:M 01 Oct 2024 14:11:02.829 * RDB age 16 seconds
grampsweb_redis  | 1:M 01 Oct 2024 14:11:02.829 * RDB memory usage when created 1.19 Mb
grampsweb_redis  | 1:M 01 Oct 2024 14:11:02.830 * Done loading RDB, keys loaded: 3, keys expired: 0.
grampsweb_redis  | 1:M 01 Oct 2024 14:11:02.830 * DB loaded from disk: 0.006 seconds
grampsweb_redis  | 1:M 01 Oct 2024 14:11:02.830 * Ready to accept connections tcp
1 Like