Troubles setting up Grampsweb with shared postgres db for multiple trees

Hi guys,

I’m trying to reinstall my grampsweb docker stack with Postgres DB, and allow it to use the shared trees addon too.

I’ve followed the documentation for it, which was quite confusing due to the varying name schemes of the environment variables.

So far, after wiping the whole directory for gramps, I get the following with the new postgres container:

CREATE DATABASE

GRANT

You are now connected to database "gramps" as user "postgres".

GRANT

CREATE EXTENSION

/usr/local/bin/docker-entrypoint.sh: sourcing /docker-entrypoint-initdb.d/20-grampswebuser.sh

CREATE ROLE

CREATE DATABASE

GRANT

You are now connected to database "grampswebuser" as user "postgres".

GRANT

CREATE EXTENSION

waiting for server to shut down...2025-04-13 16:07:59.579 UTC [49] LOG:  received fast shutdown request

.2025-04-13 16:07:59.593 UTC [49] LOG:  aborting any active transactions

2025-04-13 16:07:59.594 UTC [49] LOG:  background worker "logical replication launcher" (PID 55) exited with exit code 1

2025-04-13 16:07:59.595 UTC [50] LOG:  shutting down

2025-04-13 16:07:59.606 UTC [50] LOG:  checkpoint starting: shutdown immediate

...2025-04-13 16:08:03.545 UTC [50] LOG:  checkpoint complete: wrote 1927 buffers (11.8%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.014 s, sync=3.847 s, total=3.951 s; sync files=604, longest=0.139 s, average=0.007 s; distance=9441 kB, estimate=9441 kB

2025-04-13 16:08:03.560 UTC [49] LOG:  database system is shut down

 done

server stopped

PostgreSQL init process complete; ready for start up.

2025-04-13 16:08:03.657 UTC [1] LOG:  starting PostgreSQL 15.8 (Debian 15.8-1.pgdg120+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit

2025-04-13 16:08:03.658 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432

2025-04-13 16:08:03.658 UTC [1] LOG:  listening on IPv6 address "::", port 5432

2025-04-13 16:08:03.683 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"

2025-04-13 16:08:03.705 UTC [69] LOG:  database system was shut down at 2025-04-13 16:08:03 UTC

2025-04-13 16:08:03.750 UTC [1] LOG:  database system is ready to accept connections

2025-04-13 16:08:06.357 UTC [74] ERROR:  duplicate key value violates unique constraint "pg_type_typname_nsp_index"

2025-04-13 16:08:06.357 UTC [74] DETAIL:  Key (typname, typnamespace)=(alembic_version, 2200) already exists.

2025-04-13 16:08:06.357 UTC [74] STATEMENT:  

	CREATE TABLE alembic_version (

		version_num VARCHAR(32) NOT NULL, 

		CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)

	)

As for the grampsweb container, I get the following:

sqlalchemy.exc.IntegrityError: (psycopg2.errors.UniqueViolation) duplicate key value violates unique constraint "pg_type_typname_nsp_index"

DETAIL:  Key (typname, typnamespace)=(alembic_version, 2200) already exists.

[SQL: 

CREATE TABLE alembic_version (

	version_num VARCHAR(32) NOT NULL, 

	CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)

)

]

(Background on this error at: https://sqlalche.me/e/20/gkpj)

Traceback (most recent call last):

  File "<frozen runpy>", line 198, in _run_module_as_main

  File "<frozen runpy>", line 88, in _run_code

  File "/app/src/gramps_webapi/__main__.py", line 317, in <module>

    cli(

  File "/usr/local/lib/python3.11/dist-packages/click/core.py", line 1161, in __call__

    return self.main(*args, **kwargs)

           ^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/click/core.py", line 1082, in main

    rv = self.invoke(ctx)

         ^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/click/core.py", line 1697, in invoke

    return _process_result(sub_ctx.command.invoke(sub_ctx))

                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/click/core.py", line 1697, in invoke

    return _process_result(sub_ctx.command.invoke(sub_ctx))

                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/click/core.py", line 1443, in invoke

    return ctx.invoke(self.callback, **ctx.params)

           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/click/core.py", line 788, in invoke

    return __callback(*args, **kwargs)

           ^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/click/decorators.py", line 33, in new_func

    return f(get_current_context(), *args, **kwargs)

           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/app/src/gramps_webapi/__main__.py", line 191, in migrate_db

    subprocess.run(cmd, env=env, check=True)

  File "/usr/lib/python3.11/subprocess.py", line 571, in run

    raise CalledProcessError(retcode, process.args,

subprocess.CalledProcessError: Command '['/usr/bin/python3', '-m', 'alembic', 'upgrade', 'head']' returned non-zero exit status 1.

(__main__.py:7): Gtk-CRITICAL **: 16:08:09.427: gtk_icon_theme_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed

INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.

INFO  [alembic.runtime.migration] Will assume transactional DDL.

[2025-04-13 16:08:10 +0000] [11] [INFO] Starting gunicorn 23.0.0

[2025-04-13 16:08:10 +0000] [11] [INFO] Listening at: http://0.0.0.0:5000 (11)

[2025-04-13 16:08:10 +0000] [11] [INFO] Using worker: sync

[2025-04-13 16:08:10 +0000] [12] [INFO] Booting worker with pid: 12

[2025-04-13 16:08:10 +0000] [13] [INFO] Booting worker with pid: 13

[2025-04-13 16:08:10 +0000] [14] [INFO] Booting worker with pid: 14

[2025-04-13 16:08:10 +0000] [15] [INFO] Booting worker with pid: 15

[2025-04-13 16:08:10 +0000] [18] [INFO] Booting worker with pid: 18

[2025-04-13 16:08:10 +0000] [19] [INFO] Booting worker with pid: 19

[2025-04-13 16:08:10 +0000] [22] [INFO] Booting worker with pid: 22

[2025-04-13 16:08:10 +0000] [23] [INFO] Booting worker with pid: 23

(gunicorn:12): Gtk-CRITICAL **: 16:08:11.867: gtk_icon_theme_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed

(gunicorn:13): Gtk-CRITICAL **: 16:08:11.968: gtk_icon_theme_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed

(gunicorn:15): Gtk-CRITICAL **: 16:08:12.087: gtk_icon_theme_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed

(gunicorn:19): Gtk-CRITICAL **: 16:08:12.200: gtk_icon_theme_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed

(gunicorn:22): Gtk-CRITICAL **: 16:08:12.224: gtk_icon_theme_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed

(gunicorn:18): Gtk-CRITICAL **: 16:08:12.429: gtk_icon_theme_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed

(gunicorn:14): Gtk-CRITICAL **: 16:08:12.473: gtk_icon_theme_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed

(gunicorn:23): Gtk-CRITICAL **: 16:08:12.514: gtk_icon_theme_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed

My docker compose (without the env variables) is as follows:

services:
  grampsweb: &grampsweb
    image: ghcr.io/gramps-project/grampsweb:latest
    restart: always
    ports:
      - "5314:5000"  # host:docker
    environment:
      GRAMPSWEB_TREE: ${GRAMPSWEB_TREE}
      GRAMPSWEB_CELERY_CONFIG__broker_url: ${GRAMPSWEB_CELERY_CONFIG__broker_url}
      GRAMPSWEB_CELERY_CONFIG__result_backend: ${GRAMPSWEB_CELERY_CONFIG__result_backend}
      GRAMPSWEB_RATELIMIT_STORAGE_URI: ${GRAMPSWEB_RATELIMIT_STORAGE_URI}
      GRAMPSWEB_SECRET_KEY: ${GRAMPSWEB_SECRET_KEY}
      GRAMPSWEB_BASE_URL: ${GRAMPSWEB_BASE_URL}
      GRAMPSWEB_MEDIA_PREFIX_TREE: ${GRAMPSWEB_MEDIA_PREFIX_TREE}
      #Email
      GRAMPSWEB_EMAIL_HOST: ${GRAMPSWEB_EMAIL_HOST}
      GRAMPSWEB_EMAIL_PORT: ${GRAMPSWEB_EMAIL_PORT}
      GRAMPSWEB_EMAIL_USE_TLS: ${GRAMPSWEB_EMAIL_USE_TLS}
      GRAMPSWEB_EMAIL_HOST_USER: ${GRAMPSWEB_EMAIL_HOST_USER}
      GRAMPSWEB_EMAIL_HOST_PASSWORD: ${GRAMPSWEB_EMAIL_HOST_PASSWORD}
      GRAMPSWEB_DEFAULT_FROM_EMAIL: ${GRAMPSWEB_DEFAULT_FROM_EMAIL}
      # the PostgreSQL addon assumes the tree name to be
      # equal to the database name and here the default
      # database name of the PostgreSQL image is used
      # The credentials must agree with the ones used for
      # the PostgreSQL container
      GRAMPSWEB_POSTGRES_USER: ${GRAMPSWEB_POSTGRES_USER}
      GRAMPSWEB_POSTGRES_PASSWORD: ${GRAMPSWEB_POSTGRES_PASSWORD_GRAMPS}
      GRAMPSWEB_USER_DB_URI: ${GRAMPSWEB_USER_DB_URI}
      GRAMPSWEB_SEARCH_INDEX_DB_URI: ${GRAMPSWEB_SEARCH_INDEX_DB_URI}
      GRAMPSWEB_NEW_DB_BACKEND: ${GRAMPSWEB_NEW_DB_BACKEND}
      #A.I.
      GRAMPSWEB_LLM_BASE_URL: ${GRAMPSWEB_LLM_BASE_URL}
      GRAMPSWEB_LLM_MODEL: ${GRAMPSWEB_LLM_MODEL}
      GRAMPSWEB_VECTOR_EMBEDDING_MODEL: ${GRAMPSWEB_VECTOR_EMBEDDING_MODEL}
      GRAMPSWEB_LLM_MAX_CONTEXT_LENGTH: ${GRAMPSWEB_LLM_MAX_CONTEXT_LENGTH}
      GRAMPSWEB_OPENAI_API_KEY: ${GRAMPSWEB_OPENAI_API_KEY}
    depends_on:
      - grampsweb_redis
    volumes:
      - /mnt/tank/appdata/gramps/users:/app/users  # persist user database
      - /mnt/tank/appdata/gramps/index:/app/indexdir  # persist search index
      - /mnt/tank/appdata/gramps/thumbnail_cache:/app/thumbnail_cache  # persist thumbnails
      - /mnt/tank/appdata/gramps/cache:/app/cache  # persist export and report caches
      - /mnt/tank/appdata/gramps/secret:/app/secret  # persist flask secret
      - /mnt/tank/appdata/gramps/db:/root/.gramps/grampsdb  # persist Gramps database
      - /mnt/tank/appdata/gramps/media:/app/media  # persist media files
      - /mnt/tank/appdata/gramps/tmp:/tmp  # temporary files

  grampsweb_celery:
    <<: *grampsweb  # YAML merge key copying the entire grampsweb service config
    ports: []
    container_name: grampsweb_celery
    depends_on:
      - grampsweb_redis
    command: celery -A gramps_webapi.celery worker --loglevel=INFO

  grampsweb_redis:
    image: redis:7.2.4-alpine
    container_name: grampsweb_redis
    restart: always

  postgres_gramps:
    image: ghcr.io/davidmstraub/gramps-postgres:latest
    restart: unless-stopped
    environment:
      POSTGRES_PASSWORD: ${GRAMPSWEB_POSTGRES_PASSWORD}
      POSTGRES_PASSWORD_GRAMPS: ${GRAMPSWEB_POSTGRES_PASSWORD_GRAMPS}
      POSTGRES_PASSWORD_GRAMPS_USER: ${GRAMPSWEB_POSTGRES_PASSWORD_GRAMPS_USER}
    volumes:
      - /mnt/tank/appdata/gramps/db/postgres:/var/lib/postgresql/data

And here are the env variables, with the passwords and logins hidden, but with numbers to show whether they are different:

GRAMPSWEB_TREE=*  # will create a new tree if not exists
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
GRAMPSWEB_SECRET_KEY=#hiddenpassword4
GRAMPSWEB_BASE_URL=https://grampsweb.domain.ltd
GRAMPSWEB_EMAIL_HOST=smtp.gmail.com
GRAMPSWEB_EMAIL_PORT=587
GRAMPSWEB_EMAIL_USE_TLS=True
GRAMPSWEB_EMAIL_HOST_USER=myemail@domain.ltd
GRAMPSWEB_EMAIL_HOST_PASSWORD=#hiddensmtppassword
GRAMPSWEB_DEFAULT_FROM_EMAIL=myemail@domain.ltd
GRAMPSWEB_POSTGRES_USER=gramps
GRAMPSWEB_POSTGRES_PASSWORD=#hiddenpassword1
GRAMPSWEB_POSTGRES_PASSWORD_GRAMPS=#hiddenpassword2
GRAMPSWEB_POSTGRES_PASSWORD_GRAMPS_USER=#hiddenpassword3
GRAMPSWEB_USER_DB_URI=postgresql://grampswebuser:$GRAMPSWEB_POSTGRES_PASSWORD_GRAMPS_USER@postgres_gramps:5432/grampswebuser
GRAMPSWEB_SEARCH_INDEX_DB_URI=postgresql://gramps:$GRAMPSWEB_POSTGRES_PASSWORD_GRAMPS@postgres_gramps:5432/gramps
GRAMPSWEB_NEW_DB_BACKEND=sharedpostgresql
GRAMPSWEB_MEDIA_PREFIX_TREE=True
GRAMPSWEB_LLM_BASE_URL=
GRAMPSWEB_LLM_MODEL=gpt-4o-mini
GRAMPSWEB_VECTOR_EMBEDDING_MODEL=
GRAMPSWEB_LLM_MAX_CONTEXT_LENGTH=
GRAMPSWEB_OPENAI_API_KEY=#hidden

The documentation is quite confusing, especially due to the fact that it says to use the “GRAMPSWEB_” prefix for every variable, but then, I don’t know if it’s exactly every variable. For the postgres container, for example.

I can get to the web ui with this setup, but it’s unable to create the user. (gives a cross in a red circle).

Any help is appreciated.

Hi,

the error in the Web API container can probably be fixed by overriding the entrypoint, see this comment, can you try that?

As for the Postgres error, it seems unrelated to Gramps Web, there are some results when I google for the error message.

It still gives me an error in both containers (web and postgres).
But now it doesn’t even let me create an account, it straight asks for one.

This is the current web api container logs:

      

[SQL: SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.fullname AS users_fullname, users.pwhash AS users_pwhash, users.role AS users_role, users.tree AS users_tree 

FROM users]

(Background on this error at: https://sqlalche.me/e/20/f405)

[2025-04-13 20:00:01 +0000] [18] [ERROR] Error handling request /api/token/create_owner/

Traceback (most recent call last):

  File "/usr/local/lib/python3.11/dist-packages/sqlalchemy/engine/base.py", line 1964, in _exec_single_context

    self.dialect.do_execute(

  File "/usr/local/lib/python3.11/dist-packages/sqlalchemy/engine/default.py", line 942, in do_execute

    cursor.execute(statement, parameters)

psycopg2.errors.UndefinedTable: relation "users" does not exist

LINE 2: FROM users

             ^

The above exception was the direct cause of the following exception:

Traceback (most recent call last):

  File "/usr/local/lib/python3.11/dist-packages/gunicorn/workers/sync.py", line 134, in handle

    self.handle_request(listener, req, client, addr)

  File "/usr/local/lib/python3.11/dist-packages/gunicorn/workers/sync.py", line 177, in handle_request

    respiter = self.wsgi(environ, resp.start_response)

               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 1536, in __call__

    return self.wsgi_app(environ, start_response)

           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 1514, in wsgi_app

    response = self.handle_exception(e)

               ^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 1511, in wsgi_app

    response = self.full_dispatch_request()

               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 919, in full_dispatch_request

    rv = self.handle_user_exception(e)

         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 917, in full_dispatch_request

    rv = self.dispatch_request()

         ^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/flask/app.py", line 902, in dispatch_request

    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]

           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/flask/views.py", line 110, in view

    return current_app.ensure_sync(self.dispatch_request)(**kwargs)  # type: ignore[no-any-return]

           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/flask/views.py", line 191, in dispatch_request

    return current_app.ensure_sync(meth)(**kwargs)  # type: ignore[no-any-return]

           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/flask_limiter/extension.py", line 1297, in __inner

    return cast(R, flask.current_app.ensure_sync(obj)(*a, **k))

                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/webargs/core.py", line 657, in wrapper

    return func(*args, **kwargs)

           ^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/gramps_webapi/api/resources/token.py", line 161, in post

    if get_all_user_details(

       ^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/gramps_webapi/auth/__init__.py", line 232, in get_all_user_details

    users = query.all()

            ^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/sqlalchemy/orm/query.py", line 2699, in all

    return self._iter().all()  # type: ignore

           ^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/sqlalchemy/orm/query.py", line 2853, in _iter

    result: Union[ScalarResult[_T], Result[_T]] = self.session.execute(

                                                  ^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/sqlalchemy/orm/session.py", line 2365, in execute

    return self._execute_internal(

           ^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/sqlalchemy/orm/session.py", line 2251, in _execute_internal

    result: Result[Any] = compile_state_cls.orm_execute_statement(

                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/sqlalchemy/orm/context.py", line 305, in orm_execute_statement

    result = conn.execute(

             ^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/sqlalchemy/engine/base.py", line 1416, in execute

    return meth(

           ^^^^^

  File "/usr/local/lib/python3.11/dist-packages/sqlalchemy/sql/elements.py", line 516, in _execute_on_connection

    return connection._execute_clauseelement(

           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/sqlalchemy/engine/base.py", line 1638, in _execute_clauseelement

    ret = self._execute_context(

          ^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/sqlalchemy/engine/base.py", line 1843, in _execute_context

    return self._exec_single_context(

           ^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/local/lib/python3.11/dist-packages/sqlalchemy/engine/base.py", line 1983, in _exec_single_context

    self._handle_dbapi_exception(

  File "/usr/local/lib/python3.11/dist-packages/sqlalchemy/engine/base.py", line 2352, in _handle_dbapi_exception

    raise sqlalchemy_exception.with_traceback(exc_info[2]) from e

  File "/usr/local/lib/python3.11/dist-packages/sqlalchemy/engine/base.py", line 1964, in _exec_single_context

    self.dialect.do_execute(

  File "/usr/local/lib/python3.11/dist-packages/sqlalchemy/engine/default.py", line 942, in do_execute

    cursor.execute(statement, parameters)

sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedTable) relation "users" does not exist

LINE 2: FROM users

             ^

[SQL: SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.fullname AS users_fullname, users.pwhash AS users_pwhash, users.role AS users_role, users.tree AS users_tree 

FROM users]

(Background on this error at: https://sqlalche.me/e/20/f405)

And this is the Postgres container one:

2025-04-13 16:13:03.803 UTC [67] LOG:  checkpoint starting: time

2025-04-13 16:13:19.842 UTC [67] LOG:  checkpoint complete: wrote 162 buffers (1.0%); 0 WAL file(s) added, 0 removed, 0 recycled; write=15.942 s, sync=0.050 s, total=16.039 s; sync files=92, longest=0.032 s, average=0.001 s; distance=665 kB, estimate=665 kB

2025-04-13 19:45:59.302 UTC [1] LOG:  received fast shutdown request

2025-04-13 19:45:59.321 UTC [1] LOG:  aborting any active transactions

2025-04-13 19:45:59.324 UTC [1] LOG:  background worker "logical replication launcher" (PID 72) exited with exit code 1

2025-04-13 19:45:59.325 UTC [67] LOG:  shutting down

2025-04-13 19:45:59.335 UTC [67] LOG:  checkpoint starting: shutdown immediate

2025-04-13 19:45:59.372 UTC [67] LOG:  checkpoint complete: wrote 0 buffers (0.0%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.001 s, sync=0.001 s, total=0.048 s; sync files=0, longest=0.000 s, average=0.000 s; distance=0 kB, estimate=598 kB

2025-04-13 19:45:59.383 UTC [1] LOG:  database system is shut down

PostgreSQL Database directory appears to contain a database; Skipping initialization

2025-04-13 19:55:17.837 UTC [1] LOG:  starting PostgreSQL 15.8 (Debian 15.8-1.pgdg120+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit

2025-04-13 19:55:17.837 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432

2025-04-13 19:55:17.837 UTC [1] LOG:  listening on IPv6 address "::", port 5432

2025-04-13 19:55:17.865 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"

2025-04-13 19:55:17.898 UTC [29] LOG:  database system was shut down at 2025-04-13 19:45:59 UTC

2025-04-13 19:55:17.925 UTC [1] LOG:  database system is ready to accept connections

2025-04-13 19:58:29.565 UTC [1] LOG:  received fast shutdown request

2025-04-13 19:58:29.584 UTC [1] LOG:  aborting any active transactions

2025-04-13 19:58:29.588 UTC [1] LOG:  background worker "logical replication launcher" (PID 32) exited with exit code 1

2025-04-13 19:58:29.588 UTC [27] LOG:  shutting down

2025-04-13 19:58:29.596 UTC [27] LOG:  checkpoint starting: shutdown immediate

2025-04-13 19:58:29.669 UTC [27] LOG:  checkpoint complete: wrote 8 buffers (0.0%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.002 s, sync=0.038 s, total=0.080 s; sync files=4, longest=0.011 s, average=0.010 s; distance=0 kB, estimate=0 kB

2025-04-13 19:58:29.673 UTC [1] LOG:  database system is shut down

The files belonging to this database system will be owned by user "postgres".

This user must also own the server process.

The database cluster will be initialized with locale "en_US.utf8".

The default database encoding has accordingly been set to "UTF8".

The default text search configuration will be set to "english".

Data page checksums are disabled.

fixing permissions on existing directory /var/lib/postgresql/data ... ok

creating subdirectories ... ok

selecting dynamic shared memory implementation ... posix

selecting default max_connections ... 100

selecting default shared_buffers ... 128MB

selecting default time zone ... Etc/UTC

creating configuration files ... ok

running bootstrap script ... ok

performing post-bootstrap initialization ... ok

syncing data to disk ... ok

initdb: warning: enabling "trust" authentication for local connections

initdb: hint: You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb.

Success. You can now start the database server using:

    pg_ctl -D /var/lib/postgresql/data -l logfile start

waiting for server to start....2025-04-13 19:59:12.257 UTC [49] LOG:  starting PostgreSQL 15.8 (Debian 15.8-1.pgdg120+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit

2025-04-13 19:59:12.287 UTC [49] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"

2025-04-13 19:59:12.314 UTC [52] LOG:  database system was shut down at 2025-04-13 19:59:06 UTC

2025-04-13 19:59:12.331 UTC [49] LOG:  database system is ready to accept connections

 done

server started

/usr/local/bin/docker-entrypoint.sh: sourcing /docker-entrypoint-initdb.d/10-gramps.sh

CREATE ROLE

CREATE DATABASE

GRANT

You are now connected to database "gramps" as user "postgres".

GRANT

CREATE EXTENSION

/usr/local/bin/docker-entrypoint.sh: sourcing /docker-entrypoint-initdb.d/20-grampswebuser.sh

CREATE ROLE

CREATE DATABASE

GRANT

You are now connected to database "grampswebuser" as user "postgres".

GRANT

CREATE EXTENSION

waiting for server to shut down...2025-04-13 19:59:13.303 UTC [49] LOG:  received fast shutdown request

.2025-04-13 19:59:13.335 UTC [49] LOG:  aborting any active transactions

2025-04-13 19:59:13.337 UTC [49] LOG:  background worker "logical replication launcher" (PID 55) exited with exit code 1

2025-04-13 19:59:13.337 UTC [50] LOG:  shutting down

2025-04-13 19:59:13.369 UTC [50] LOG:  checkpoint starting: shutdown immediate



Current docker compose:

services:
  grampsweb: &grampsweb
    image: ghcr.io/gramps-project/grampsweb:latest
    restart: always
    ports:
      - "5314:5000"  # host:docker
    environment:
      GRAMPSWEB_TREE: ${GRAMPSWEB_TREE}
      GRAMPSWEB_CELERY_CONFIG__broker_url: ${GRAMPSWEB_CELERY_CONFIG__broker_url}
      GRAMPSWEB_CELERY_CONFIG__result_backend: ${GRAMPSWEB_CELERY_CONFIG__result_backend}
      GRAMPSWEB_RATELIMIT_STORAGE_URI: ${GRAMPSWEB_RATELIMIT_STORAGE_URI}
      GRAMPSWEB_SECRET_KEY: ${GRAMPSWEB_SECRET_KEY}
      GRAMPSWEB_BASE_URL: ${GRAMPSWEB_BASE_URL}
      GRAMPSWEB_MEDIA_PREFIX_TREE: ${GRAMPSWEB_MEDIA_PREFIX_TREE}
      #Email
      GRAMPSWEB_EMAIL_HOST: ${GRAMPSWEB_EMAIL_HOST}
      GRAMPSWEB_EMAIL_PORT: ${GRAMPSWEB_EMAIL_PORT}
      GRAMPSWEB_EMAIL_USE_TLS: ${GRAMPSWEB_EMAIL_USE_TLS}
      GRAMPSWEB_EMAIL_HOST_USER: ${GRAMPSWEB_EMAIL_HOST_USER}
      GRAMPSWEB_EMAIL_HOST_PASSWORD: ${GRAMPSWEB_EMAIL_HOST_PASSWORD}
      GRAMPSWEB_DEFAULT_FROM_EMAIL: ${GRAMPSWEB_DEFAULT_FROM_EMAIL}
      # the PostgreSQL addon assumes the tree name to be
      # equal to the database name and here the default
      # database name of the PostgreSQL image is used
      # The credentials must agree with the ones used for
      # the PostgreSQL container
      GRAMPSWEB_POSTGRES_USER: ${GRAMPSWEB_POSTGRES_USER}
      GRAMPSWEB_POSTGRES_PASSWORD: ${GRAMPSWEB_POSTGRES_PASSWORD_GRAMPS}
      GRAMPSWEB_USER_DB_URI: ${GRAMPSWEB_USER_DB_URI}
      GRAMPSWEB_SEARCH_INDEX_DB_URI: ${GRAMPSWEB_SEARCH_INDEX_DB_URI}
      GRAMPSWEB_NEW_DB_BACKEND: ${GRAMPSWEB_NEW_DB_BACKEND}
      #A.I.
      GRAMPSWEB_LLM_BASE_URL: ${GRAMPSWEB_LLM_BASE_URL}
      GRAMPSWEB_LLM_MODEL: ${GRAMPSWEB_LLM_MODEL}
      GRAMPSWEB_VECTOR_EMBEDDING_MODEL: ${GRAMPSWEB_VECTOR_EMBEDDING_MODEL}
      GRAMPSWEB_LLM_MAX_CONTEXT_LENGTH: ${GRAMPSWEB_LLM_MAX_CONTEXT_LENGTH}
      GRAMPSWEB_OPENAI_API_KEY: ${GRAMPSWEB_OPENAI_API_KEY}
    entrypoint: []
    depends_on:
      - grampsweb_redis
    volumes:
      - /mnt/tank/appdata/gramps/users:/app/users  # persist user database
      - /mnt/tank/appdata/gramps/index:/app/indexdir  # persist search index
      - /mnt/tank/appdata/gramps/thumbnail_cache:/app/thumbnail_cache  # persist thumbnails
      - /mnt/tank/appdata/gramps/cache:/app/cache  # persist export and report caches
      - /mnt/tank/appdata/gramps/secret:/app/secret  # persist flask secret
      - /mnt/tank/appdata/gramps/db:/root/.gramps/grampsdb  # persist Gramps database
      - /mnt/tank/appdata/gramps/media:/app/media  # persist media files
      - /mnt/tank/appdata/gramps/tmp:/tmp  # temporary files

  grampsweb_celery:
    <<: *grampsweb  # YAML merge key copying the entire grampsweb service config
    ports: []
    container_name: grampsweb_celery
    depends_on:
      - grampsweb_redis
    command: celery -A gramps_webapi.celery worker --loglevel=INFO

  grampsweb_redis:
    image: redis:7.2.4-alpine
    container_name: grampsweb_redis
    restart: always

  postgres_gramps:
    image: ghcr.io/davidmstraub/gramps-postgres:latest
    restart: unless-stopped
    environment:
      POSTGRES_PASSWORD: ${GRAMPSWEB_POSTGRES_PASSWORD}
      POSTGRES_PASSWORD_GRAMPS: ${GRAMPSWEB_POSTGRES_PASSWORD_GRAMPS}
      POSTGRES_PASSWORD_GRAMPS_USER: ${GRAMPSWEB_POSTGRES_PASSWORD_GRAMPS_USER}
    volumes:
      - /mnt/tank/appdata/gramps/db/postgres:/var/lib/postgresql/data

Web view:

Wouldn’t you have a ready-to-go docker compose for the shared tree version using postgressql?

Maybe there is something wrong with mine.

Does it necessarily use the user grampswebuser?
Or can I just set a single password instead of the 3 I’m using, and also define one user?

Like:

GRAMPSWEB_POSTGRES_USER=gramps
GRAMPSWEB_POSTGRES_PASSWORD=password1

?

I think it’s having issues connecting to the DB. It keeps saying wrong password.

Update:

I set up the same password for the 3 variables. It doesn’t matter.
No idea what’s going on. Maybe it’s not recognizing the names of the variables and defining default ones.

You can also try wiping the Postgres volumes and starting over. It could be that the Postgres container was initialized while you had an inconsistent coinfiguration and now it’s stuck.

Hey,

Every time I modify the env variables or the compose, I wipe the whole thing.

Still not working.

Wouldn’t you have per chance a working compose and env variables with this multi-tree shared postgres setup for me to compare? You can hide the passwords like password1, password2,…

Thanks for the help!

Is there anyone that could help me with this? We could do a Discord call or something so I can share my screen if needed.
I’d love to get this working.

Currently getting this with the Postgres container:

PostgreSQL init process complete; ready for start up.

2025-04-16 17:23:12.678 UTC [1] LOG:  starting PostgreSQL 15.8 (Debian 15.8-1.pgdg120+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit

2025-04-16 17:23:12.678 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432

2025-04-16 17:23:12.678 UTC [1] LOG:  listening on IPv6 address "::", port 5432

2025-04-16 17:23:12.693 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"

2025-04-16 17:23:12.708 UTC [69] LOG:  database system was shut down at 2025-04-16 17:23:12 UTC

2025-04-16 17:23:12.738 UTC [1] LOG:  database system is ready to accept connections

2025-04-16 17:23:48.652 UTC [75] ERROR:  relation "users" does not exist at character 205

2025-04-16 17:23:48.652 UTC [75] STATEMENT:  SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.fullname AS users_fullname, users.pwhash AS users_pwhash, users.role AS users_role, users.tree AS users_tree 

	FROM users

After removing the docker entrypoint, you might have to manually create the user database tables. Try

python3 -m gramps_webapi --config /app/config/config.cfg user migrate

in the Web API container

root@3395a5f9ccbc:/app# python3 -m gramps_webapi --config /app/config/config.cfg user migrate

(__main__.py:30): Gtk-CRITICAL **: 17:39:52.856: gtk_icon_theme_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed
  FAILED: No config file 'alembic.ini' found, or file has no '[alembic]' section
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/usr/local/lib/python3.11/dist-packages/gramps_webapi/__main__.py", line 317, in <module>
    cli(
  File "/usr/local/lib/python3.11/dist-packages/click/core.py", line 1161, in __call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/click/core.py", line 1082, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/click/core.py", line 1697, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/click/core.py", line 1697, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/click/core.py", line 1443, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/click/core.py", line 788, in invoke
    return __callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/click/decorators.py", line 33, in new_func
    return f(get_current_context(), *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/gramps_webapi/__main__.py", line 191, in migrate_db
    subprocess.run(cmd, env=env, check=True)
  File "/usr/lib/python3.11/subprocess.py", line 571, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['/usr/bin/python3', '-m', 'alembic', 'upgrade', 'head']' returned non-zero exit status 255.

Gave me this.

By the way

This is exaplained here Server configuration - Gramps Web.

Oh, now I see what your problem could be.

POSTGRES_PASSWORD, POSTGRES_PASSWORD_GRAMPS and POSTGRES_PASSWORD_GRAMPS_USER are not Gramps Web configuration settings. They are environment variables of the gramps-postgres-docker Docker image. That’s why here there is no GRAMPSWEB_ prefix (as this has nothing to do with Flask settings).

Hmm, I mean, I still have them set like they are in the guide (no GRAMPSWEB_ prefix for the postgres container). It still doesn’t work. Here is my current docker compose:

services:
  grampsweb: &grampsweb
    image: ghcr.io/gramps-project/grampsweb:latest
    restart: always
    ports:
      - "5314:5000"  # host:docker
    environment:
      GRAMPSWEB_TREE: ${GRAMPSWEB_TREE}
      GRAMPSWEB_CELERY_CONFIG__broker_url: ${GRAMPSWEB_CELERY_CONFIG__broker_url}
      GRAMPSWEB_CELERY_CONFIG__result_backend: ${GRAMPSWEB_CELERY_CONFIG__result_backend}
      GRAMPSWEB_RATELIMIT_STORAGE_URI: ${GRAMPSWEB_RATELIMIT_STORAGE_URI}
      GRAMPSWEB_SECRET_KEY: ${GRAMPSWEB_SECRET_KEY}
      GRAMPSWEB_BASE_URL: ${GRAMPSWEB_BASE_URL}
      GRAMPSWEB_MEDIA_PREFIX_TREE: ${GRAMPSWEB_MEDIA_PREFIX_TREE}
      #Email
      GRAMPSWEB_EMAIL_HOST: ${GRAMPSWEB_EMAIL_HOST}
      GRAMPSWEB_EMAIL_PORT: ${GRAMPSWEB_EMAIL_PORT}
      GRAMPSWEB_EMAIL_USE_TLS: ${GRAMPSWEB_EMAIL_USE_TLS}
      GRAMPSWEB_EMAIL_HOST_USER: ${GRAMPSWEB_EMAIL_HOST_USER}
      GRAMPSWEB_EMAIL_HOST_PASSWORD: ${GRAMPSWEB_EMAIL_HOST_PASSWORD}
      GRAMPSWEB_DEFAULT_FROM_EMAIL: ${GRAMPSWEB_DEFAULT_FROM_EMAIL}
      # the PostgreSQL addon assumes the tree name to be
      # equal to the database name and here the default
      # database name of the PostgreSQL image is used
      # The credentials must agree with the ones used for
      # the PostgreSQL container
      GRAMPSWEB_POSTGRES_USER: ${GRAMPSWEB_POSTGRES_USER}
      GRAMPSWEB_POSTGRES_PASSWORD: ${POSTGRES_PASSWORD_GRAMPS}
      GRAMPSWEB_USER_DB_URI: ${GRAMPSWEB_USER_DB_URI}
      GRAMPSWEB_SEARCH_INDEX_DB_URI: ${GRAMPSWEB_SEARCH_INDEX_DB_URI}
      GRAMPSWEB_NEW_DB_BACKEND: ${GRAMPSWEB_NEW_DB_BACKEND}
      #A.I.
      GRAMPSWEB_LLM_BASE_URL: ${GRAMPSWEB_LLM_BASE_URL}
      GRAMPSWEB_LLM_MODEL: ${GRAMPSWEB_LLM_MODEL}
      GRAMPSWEB_VECTOR_EMBEDDING_MODEL: ${GRAMPSWEB_VECTOR_EMBEDDING_MODEL}
      GRAMPSWEB_LLM_MAX_CONTEXT_LENGTH: ${GRAMPSWEB_LLM_MAX_CONTEXT_LENGTH}
      GRAMPSWEB_OPENAI_API_KEY: ${GRAMPSWEB_OPENAI_API_KEY}
    entrypoint: []
    depends_on:
      - grampsweb_redis
    volumes:
      - /mnt/tank/appdata/grampsweb/users:/app/users  # persist user database
      - /mnt/tank/appdata/grampsweb/index:/app/indexdir  # persist search index
      - /mnt/tank/appdata/grampsweb/thumbnail_cache:/app/thumbnail_cache  # persist thumbnails
      - /mnt/tank/appdata/grampsweb/cache:/app/cache  # persist export and report caches
      - /mnt/tank/appdata/grampsweb/secret:/app/secret  # persist flask secret
      - /mnt/tank/appdata/grampsweb/db:/root/.gramps/grampsdb  # persist Gramps database
      - /mnt/tank/appdata/grampsweb/media:/app/media  # persist media files
      - /mnt/tank/appdata/grampsweb/tmp:/tmp  # temporary files

  grampsweb_celery:
    <<: *grampsweb  # YAML merge key copying the entire grampsweb service config
    ports: []
    container_name: grampsweb_celery
    depends_on:
      - grampsweb_redis
    command: celery -A gramps_webapi.celery worker --loglevel=INFO

  grampsweb_redis:
    image: redis:7.2.4-alpine
    container_name: grampsweb_redis
    restart: always

  postgres_gramps:
    image: ghcr.io/davidmstraub/gramps-postgres:latest
    restart: unless-stopped
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_PASSWORD_GRAMPS: ${POSTGRES_PASSWORD_GRAMPS}
      POSTGRES_PASSWORD_GRAMPS_USER: ${POSTGRES_PASSWORD_GRAMPS_USER}
    volumes:
      - /mnt/tank/appdata/grampsweb/postgres:/var/lib/postgresql/data

As you can see in the postgres env variables, I still have them set like in the guide:

      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_PASSWORD_GRAMPS: ${POSTGRES_PASSWORD_GRAMPS}
      POSTGRES_PASSWORD_GRAMPS_USER: ${POSTGRES_PASSWORD_GRAMPS_USER}

I have the current env variables for the webui container, related to the db:

# DB Section
      GRAMPSWEB_POSTGRES_USER: ${GRAMPSWEB_POSTGRES_USER}
      GRAMPSWEB_POSTGRES_PASSWORD: ${POSTGRES_PASSWORD_GRAMPS}
      GRAMPSWEB_USER_DB_URI: ${GRAMPSWEB_USER_DB_URI}
      GRAMPSWEB_SEARCH_INDEX_DB_URI: ${GRAMPSWEB_SEARCH_INDEX_DB_URI}
      GRAMPSWEB_NEW_DB_BACKEND: ${GRAMPSWEB_NEW_DB_BACKEND}

And here is the config for the GRAMPSWEB_TREE:

GRAMPSWEB_TREE: ${GRAMPSWEB_TREE}

References to:

GRAMPSWEB_TREE=*

Here are the relevant environment variable values:

GRAMPSWEB_TREE=*
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
GRAMPSWEB_SECRET_KEY=#hidden-password4
GRAMPSWEB_POSTGRES_USER=gramps
POSTGRES_PASSWORD=#hidden-password1
POSTGRES_PASSWORD_GRAMPS=#hidden-password2
POSTGRES_PASSWORD_GRAMPS_USER=#hidden-password3
GRAMPSWEB_USER_DB_URI=postgresql://grampswebuser:#hidden-password3@postgres_gramps:5432/grampswebuser
GRAMPSWEB_SEARCH_INDEX_DB_URI=postgresql://gramps:#hidden-password2@postgres_gramps:5432/gramps
GRAMPSWEB_NEW_DB_BACKEND=sharedpostgresql
GRAMPSWEB_MEDIA_PREFIX_TREE=True

I have the passwords hidden, but you can see where they are used.

I’ve completely followed the guides available, no idea what else I should do.

For info, I wipe the whole directory each time I make these changes.

For the moment, it seems like it can’t create the users table.