diff --git a/.env.example b/.env.example index 4dc73b56e..e799c489d 100644 --- a/.env.example +++ b/.env.example @@ -22,5 +22,9 @@ # TRAEFIK_HTTP_PORT=80 # TRAEFIK_HTTPS_PORT=443 -# Public base URL PhotoPrism advertises in share links, OIDC & PWA URIs. +# Public base URL used in share links, OIDC & PWA URIs. # PHOTOPRISM_SITE_URL=https://app.localssl.dev/ + +# Ports to which MariaDB and PostgreSQL should bind. +# MARIADB_PORT=4001 +# POSTGRES_PORT=5432 diff --git a/.my.cnf b/.my.cnf index fc2637052..886305f5e 100644 --- a/.my.cnf +++ b/.my.cnf @@ -2,5 +2,4 @@ user=root password=photoprism host=mariadb -port=4001 skip-ssl=true \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index e193ca467..2011bf0bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,4 +25,9 @@ WORKDIR "/go/src/github.com/photoprism/photoprism" COPY . . COPY --chown=root:root /scripts/dist/ /scripts/ +# Re-install the dev "mariadb" client config so a custom MARIADB_PORT in .env +# is honored even when the base image was built before the port= line was +# removed (no-op once the next dated base image picks up the new .my.cnf). +COPY --chown=root:root --chmod=644 .my.cnf /etc/my.cnf + RUN sudo /scripts/install-yt-dlp.sh diff --git a/Makefile b/Makefile index 3e9a66fbd..ef9c877a0 100644 --- a/Makefile +++ b/Makefile @@ -528,7 +528,7 @@ run-test-hub: env PHOTOPRISM_TEST_HUB="true" $(GOTEST) -parallel 1 -count 1 -cpu 1 -tags="slow,develop,debug" -timeout 20m ./pkg/... ./internal/... run-test-mariadb: $(info Running all Go tests on MariaDB...) - PHOTOPRISM_TEST_DRIVER="mysql" PHOTOPRISM_TEST_DSN="root:photoprism@tcp(mariadb:4001)/acceptance?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true" $(GOTEST) -parallel 1 -count 1 -cpu 1 -tags="slow,develop" -timeout 20m ./pkg/... ./internal/... + PHOTOPRISM_TEST_DRIVER="mysql" PHOTOPRISM_TEST_DSN="root:photoprism@tcp(mariadb:$${MARIADB_PORT:-4001})/acceptance?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true" $(GOTEST) -parallel 1 -count 1 -cpu 1 -tags="slow,develop" -timeout 20m ./pkg/... ./internal/... run-test-pkg: $(info Running all Go tests in "/pkg"...) $(GOTEST) -parallel 2 -count 1 -cpu 2 -tags="slow,develop" -timeout 20m ./pkg/... diff --git a/compose.armv7.yaml b/compose.armv7.yaml index f62cf1af3..003a27f83 100644 --- a/compose.armv7.yaml +++ b/compose.armv7.yaml @@ -34,14 +34,15 @@ services: PHOTOPRISM_HTTP_HOST: "0.0.0.0" PHOTOPRISM_HTTP_PORT: 2342 PHOTOPRISM_HTTP_COMPRESSION: "zstd,gzip" # Improves transfer speed and bandwidth utilization (none, gzip, zstd, or comma-separated list e.g. "zstd,gzip") + MYSQL_TCP_PORT: "${MARIADB_PORT:-4001}" # default port used by the "mariadb" client (see .my.cnf) PHOTOPRISM_DATABASE_DRIVER: "mysql" - PHOTOPRISM_DATABASE_SERVER: "mariadb:4001" + PHOTOPRISM_DATABASE_SERVER: "mariadb:${MARIADB_PORT:-4001}" PHOTOPRISM_DATABASE_NAME: "photoprism" PHOTOPRISM_DATABASE_USER: "root" PHOTOPRISM_DATABASE_PASSWORD: "photoprism" PHOTOPRISM_TEST_DRIVER: "sqlite" PHOTOPRISM_TEST_DSN: ".test.db" - # PHOTOPRISM_TEST_DSN_MYSQL8: "root:photoprism@tcp(mysql:4001)/photoprism?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true&timeout=15s" + # PHOTOPRISM_TEST_DSN_MYSQL8: "root:photoprism@tcp(mysql:${MARIADB_PORT:-4001})/photoprism?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true&timeout=15s" PHOTOPRISM_ASSETS_PATH: "/go/src/github.com/photoprism/photoprism/assets" PHOTOPRISM_STORAGE_PATH: "/go/src/github.com/photoprism/photoprism/storage" PHOTOPRISM_ORIGINALS_PATH: "/go/src/github.com/photoprism/photoprism/storage/originals" @@ -92,11 +93,11 @@ services: security_opt: # see https://github.com/MariaDB/mariadb-docker/issues/434#issuecomment-1136151239 - seccomp:unconfined - apparmor:unconfined - command: --port=4001 --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 + command: --port=${MARIADB_PORT:-4001} --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 expose: - - "4001" + - "${MARIADB_PORT:-4001}" ports: - - "4001:4001" # database port (host:container) + - "${MARIADB_PORT:-4001}:${MARIADB_PORT:-4001}" # database port (host:container) volumes: - "./scripts/sql/mariadb-init.sql:/docker-entrypoint-initdb.d/init.sql" environment: @@ -124,5 +125,5 @@ volumes: ## Create shared "photoprism" network for connecting with services in other compose.yaml files networks: default: - name: photoprism + name: ${COMPOSE_NETWORK_NAME:-photoprism} driver: bridge diff --git a/compose.intel.yaml b/compose.intel.yaml index 9732fc7fe..73164d3f8 100644 --- a/compose.intel.yaml +++ b/compose.intel.yaml @@ -28,7 +28,7 @@ services: - "traefik:dummy-webdav.localssl.dev" labels: - "traefik.enable=true" - - "traefik.docker.network=photoprism" + - "traefik.docker.network=${COMPOSE_NETWORK_NAME:-photoprism}" - "traefik.http.services.photoprism.loadbalancer.server.port=2342" - "traefik.http.services.photoprism.loadbalancer.server.scheme=http" - "traefik.http.routers.photoprism.entrypoints=websecure" @@ -94,13 +94,14 @@ services: PHOTOPRISM_HTTP_HOST: "0.0.0.0" PHOTOPRISM_HTTP_PORT: 2342 PHOTOPRISM_HTTP_COMPRESSION: "zstd,gzip" # improves transfer speed and bandwidth utilization (none, gzip, zstd, or comma-separated list e.g. "zstd,gzip") + MYSQL_TCP_PORT: "${MARIADB_PORT:-4001}" # default port used by the "mariadb" client (see .my.cnf) PHOTOPRISM_DATABASE_DRIVER: "mysql" - PHOTOPRISM_DATABASE_SERVER: "mariadb:4001" + PHOTOPRISM_DATABASE_SERVER: "mariadb:${MARIADB_PORT:-4001}" PHOTOPRISM_DATABASE_NAME: "photoprism" PHOTOPRISM_DATABASE_USER: "root" PHOTOPRISM_DATABASE_PASSWORD: "photoprism" PHOTOPRISM_TEST_DRIVER: "sqlite" - # PHOTOPRISM_TEST_DSN_MYSQL8: "root:photoprism@tcp(mysql:4001)/photoprism?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true&timeout=15s" + # PHOTOPRISM_TEST_DSN_MYSQL8: "root:photoprism@tcp(mysql:${MARIADB_PORT:-4001})/photoprism?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true&timeout=15s" PHOTOPRISM_ASSETS_PATH: "/go/src/github.com/photoprism/photoprism/assets" PHOTOPRISM_STORAGE_PATH: "/go/src/github.com/photoprism/photoprism/storage" PHOTOPRISM_ORIGINALS_PATH: "/go/src/github.com/photoprism/photoprism/storage/originals" @@ -195,5 +196,5 @@ volumes: ## Create shared "photoprism" network for connecting with services in other compose.yaml files networks: default: - name: photoprism + name: ${COMPOSE_NETWORK_NAME:-photoprism} driver: bridge diff --git a/compose.latest.yaml b/compose.latest.yaml index 53462c150..52bec2171 100644 --- a/compose.latest.yaml +++ b/compose.latest.yaml @@ -12,7 +12,7 @@ services: - "2344:2342" # HTTP port (host:container) labels: - "traefik.enable=true" - - "traefik.docker.network=photoprism" + - "traefik.docker.network=${COMPOSE_NETWORK_NAME:-photoprism}" - "traefik.http.services.latest.loadbalancer.server.port=2342" - "traefik.http.routers.latest.entrypoints=websecure" - "traefik.http.routers.latest.rule=Host(`latest.localssl.dev`)" @@ -38,7 +38,7 @@ services: PHOTOPRISM_HTTP_PORT: 2342 PHOTOPRISM_HTTP_COMPRESSION: "zstd,gzip" # improves transfer speed and bandwidth utilization (none, gzip, zstd, or comma-separated list e.g. "zstd,gzip") PHOTOPRISM_DATABASE_DRIVER: "mysql" - PHOTOPRISM_DATABASE_SERVER: "mariadb:4001" + PHOTOPRISM_DATABASE_SERVER: "mariadb:${MARIADB_PORT:-4001}" PHOTOPRISM_DATABASE_NAME: "photoprism" PHOTOPRISM_DATABASE_USER: "root" PHOTOPRISM_DATABASE_PASSWORD: "photoprism" @@ -69,5 +69,5 @@ services: ## Join shared "photoprism" network networks: default: - name: photoprism + name: ${COMPOSE_NETWORK_NAME:-photoprism} external: true diff --git a/compose.local.yaml b/compose.local.yaml index b02e15cb6..8b65086e6 100644 --- a/compose.local.yaml +++ b/compose.local.yaml @@ -14,7 +14,7 @@ services: - "2345:2342" # HTTP port (host:container) labels: - "traefik.enable=true" - - "traefik.docker.network=photoprism" + - "traefik.docker.network=${COMPOSE_NETWORK_NAME:-photoprism}" - "traefik.http.services.latest.loadbalancer.server.port=2342" - "traefik.http.routers.latest.entrypoints=websecure" - "traefik.http.routers.latest.rule=Host(`local.localssl.dev`)" @@ -39,7 +39,7 @@ services: PHOTOPRISM_HTTP_PORT: 2342 PHOTOPRISM_HTTP_COMPRESSION: "zstd,gzip" # improves transfer speed and bandwidth utilization (none, gzip, zstd, or comma-separated list e.g. "zstd,gzip") PHOTOPRISM_DATABASE_DRIVER: "mysql" - PHOTOPRISM_DATABASE_SERVER: "mariadb:4001" + PHOTOPRISM_DATABASE_SERVER: "mariadb:${MARIADB_PORT:-4001}" PHOTOPRISM_DATABASE_NAME: "local" PHOTOPRISM_DATABASE_USER: "local" PHOTOPRISM_DATABASE_PASSWORD: "local" @@ -76,5 +76,5 @@ services: ## Join shared "photoprism" network networks: default: - name: photoprism + name: ${COMPOSE_NETWORK_NAME:-photoprism} external: true diff --git a/compose.mariadb.yaml b/compose.mariadb.yaml index d5e245fc7..b84e48d4b 100644 --- a/compose.mariadb.yaml +++ b/compose.mariadb.yaml @@ -10,9 +10,9 @@ services: security_opt: # see https://github.com/MariaDB/mariadb-docker/issues/434#issuecomment-1136151239 - seccomp:unconfined - apparmor:unconfined - command: --port=4001 --innodb-strict-mode=1 --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 + command: --port=${MARIADB_PORT:-4001} --innodb-strict-mode=1 --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 expose: - - "4001" + - "${MARIADB_PORT:-4001}" volumes: - "./scripts/sql/mariadb-init.sql:/docker-entrypoint-initdb.d/init.sql" environment: @@ -31,9 +31,9 @@ services: security_opt: # see https://github.com/MariaDB/mariadb-docker/issues/434#issuecomment-1136151239 - seccomp:unconfined - apparmor:unconfined - command: --port=4001 --innodb-strict-mode=1 --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 + command: --port=${MARIADB_PORT:-4001} --innodb-strict-mode=1 --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 expose: - - "4001" + - "${MARIADB_PORT:-4001}" volumes: - "./scripts/sql/mariadb-init.sql:/docker-entrypoint-initdb.d/init.sql" environment: @@ -52,9 +52,9 @@ services: security_opt: # see https://github.com/MariaDB/mariadb-docker/issues/434#issuecomment-1136151239 - seccomp:unconfined - apparmor:unconfined - command: --port=4001 --innodb-strict-mode=1 --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 + command: --port=${MARIADB_PORT:-4001} --innodb-strict-mode=1 --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 expose: - - "4001" + - "${MARIADB_PORT:-4001}" volumes: - "./scripts/sql/mariadb-init.sql:/docker-entrypoint-initdb.d/init.sql" environment: @@ -72,9 +72,9 @@ services: security_opt: # see https://github.com/MariaDB/mariadb-docker/issues/434#issuecomment-1136151239 - seccomp:unconfined - apparmor:unconfined - command: --port=4001 --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 + command: --port=${MARIADB_PORT:-4001} --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 expose: - - "4001" + - "${MARIADB_PORT:-4001}" volumes: - "./scripts/sql/mariadb-init.sql:/docker-entrypoint-initdb.d/init.sql" environment: @@ -90,9 +90,9 @@ services: ## see https://jira.mariadb.org/browse/MDEV-25362 mariadb-10-5-5: image: mariadb:10.5.5 - command: --port=4001 --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 + command: --port=${MARIADB_PORT:-4001} --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 expose: - - "4001" # database port (internal) + - "${MARIADB_PORT:-4001}" # database port (internal) volumes: - "./scripts/sql/mariadb-init.sql:/docker-entrypoint-initdb.d/init.sql" environment: @@ -105,9 +105,9 @@ services: ## Docs: https://mariadb.com/docs/reference/cs10.3/ mariadb-10-3: image: mariadb:10.3 - command: --port=4001 --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 + command: --port=${MARIADB_PORT:-4001} --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 expose: - - "4001" # database port (internal) + - "${MARIADB_PORT:-4001}" # database port (internal) volumes: - "./scripts/sql/mariadb-init.sql:/docker-entrypoint-initdb.d/init.sql" environment: @@ -120,9 +120,9 @@ services: ## Docs: https://mariadb.com/docs/reference/cs10.2/ mariadb-10-2: image: mariadb:10.2 - command: --port=4001 --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 + command: --port=${MARIADB_PORT:-4001} --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 expose: - - "4001" # database port (internal) + - "${MARIADB_PORT:-4001}" # database port (internal) volumes: - "./scripts/sql/mariadb-init.sql:/docker-entrypoint-initdb.d/init.sql" environment: @@ -134,9 +134,9 @@ services: ## MariaDB 10.1 Database Server mariadb-10-1: image: mariadb:10.1 - command: --port=4001 --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 + command: --port=${MARIADB_PORT:-4001} --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 expose: - - "4001" # database port (internal) + - "${MARIADB_PORT:-4001}" # database port (internal) volumes: - "./scripts/sql/mariadb-init.sql:/docker-entrypoint-initdb.d/init.sql" environment: @@ -148,5 +148,5 @@ services: ## Join shared "photoprism" network networks: default: - name: photoprism + name: ${COMPOSE_NETWORK_NAME:-photoprism} external: true diff --git a/compose.mysql.yaml b/compose.mysql.yaml index 851a1284f..8ca083c5d 100644 --- a/compose.mysql.yaml +++ b/compose.mysql.yaml @@ -6,9 +6,9 @@ services: ## Docs: https://dev.mysql.com/doc/refman/8.0/en/ mysql: image: mysql:8 - command: --port=4001 --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 + command: --port=${MARIADB_PORT:-4001} --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 expose: - - "4001" # database port (internal) + - "${MARIADB_PORT:-4001}" # database port (internal) environment: MYSQL_DATABASE: "photoprism" MYSQL_USER: "photoprism" @@ -18,5 +18,5 @@ services: ## Join shared "photoprism" network networks: default: - name: photoprism + name: ${COMPOSE_NETWORK_NAME:-photoprism} external: true diff --git a/compose.nvidia.yaml b/compose.nvidia.yaml index a2d4588e4..6d10860d4 100644 --- a/compose.nvidia.yaml +++ b/compose.nvidia.yaml @@ -31,7 +31,7 @@ services: - "traefik:dummy-webdav.localssl.dev" labels: - "traefik.enable=true" - - "traefik.docker.network=photoprism" + - "traefik.docker.network=${COMPOSE_NETWORK_NAME:-photoprism}" - "traefik.http.services.photoprism.loadbalancer.server.port=2342" - "traefik.http.services.photoprism.loadbalancer.server.scheme=http" - "traefik.http.routers.photoprism.entrypoints=websecure" @@ -97,13 +97,14 @@ services: PHOTOPRISM_HTTP_HOST: "0.0.0.0" PHOTOPRISM_HTTP_PORT: 2342 PHOTOPRISM_HTTP_COMPRESSION: "zstd,gzip" # improves transfer speed and bandwidth utilization (none, gzip, zstd, or comma-separated list e.g. "zstd,gzip") + MYSQL_TCP_PORT: "${MARIADB_PORT:-4001}" # default port used by the "mariadb" client (see .my.cnf) PHOTOPRISM_DATABASE_DRIVER: "mysql" - PHOTOPRISM_DATABASE_SERVER: "mariadb:4001" + PHOTOPRISM_DATABASE_SERVER: "mariadb:${MARIADB_PORT:-4001}" PHOTOPRISM_DATABASE_NAME: "photoprism" PHOTOPRISM_DATABASE_USER: "root" PHOTOPRISM_DATABASE_PASSWORD: "photoprism" PHOTOPRISM_TEST_DRIVER: "sqlite" - # PHOTOPRISM_TEST_DSN_MYSQL8: "root:photoprism@tcp(mysql:4001)/photoprism?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true&timeout=15s" + # PHOTOPRISM_TEST_DSN_MYSQL8: "root:photoprism@tcp(mysql:${MARIADB_PORT:-4001})/photoprism?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true&timeout=15s" PHOTOPRISM_ASSETS_PATH: "/go/src/github.com/photoprism/photoprism/assets" PHOTOPRISM_STORAGE_PATH: "/go/src/github.com/photoprism/photoprism/storage" PHOTOPRISM_ORIGINALS_PATH: "/go/src/github.com/photoprism/photoprism/storage/originals" @@ -178,7 +179,7 @@ services: # - "11434:11434" labels: - "traefik.enable=true" - - "traefik.docker.network=photoprism" + - "traefik.docker.network=${COMPOSE_NETWORK_NAME:-photoprism}" - "traefik.http.services.ollama.loadbalancer.server.port=11434" - "traefik.http.routers.ollama.rule=Host(`ollama.localssl.dev`)" - "traefik.http.routers.ollama.entrypoints=websecure" @@ -267,5 +268,5 @@ volumes: ## Create shared "photoprism" network for connecting with services in other compose.yaml files networks: default: - name: photoprism + name: ${COMPOSE_NETWORK_NAME:-photoprism} driver: bridge diff --git a/compose.preview.yaml b/compose.preview.yaml index 95388e0c9..d67c51340 100644 --- a/compose.preview.yaml +++ b/compose.preview.yaml @@ -12,7 +12,7 @@ services: - "2344:2342" # HTTP port (host:container) labels: - "traefik.enable=true" - - "traefik.docker.network=photoprism" + - "traefik.docker.network=${COMPOSE_NETWORK_NAME:-photoprism}" - "traefik.http.services.preview.loadbalancer.server.port=2342" - "traefik.http.routers.preview.entrypoints=websecure" - "traefik.http.routers.preview.rule=Host(`preview.localssl.dev`)" @@ -38,7 +38,7 @@ services: PHOTOPRISM_HTTP_PORT: 2342 PHOTOPRISM_HTTP_COMPRESSION: "zstd,gzip" # improves transfer speed and bandwidth utilization (none, gzip, zstd, or comma-separated list e.g. "zstd,gzip") PHOTOPRISM_DATABASE_DRIVER: "mysql" - PHOTOPRISM_DATABASE_SERVER: "mariadb:4001" + PHOTOPRISM_DATABASE_SERVER: "mariadb:${MARIADB_PORT:-4001}" PHOTOPRISM_DATABASE_NAME: "photoprism" PHOTOPRISM_DATABASE_USER: "root" PHOTOPRISM_DATABASE_PASSWORD: "photoprism" @@ -69,5 +69,5 @@ services: ## Join shared "photoprism" network networks: default: - name: photoprism + name: ${COMPOSE_NETWORK_NAME:-photoprism} external: true diff --git a/compose.yaml b/compose.yaml index e36311719..87d6748fd 100644 --- a/compose.yaml +++ b/compose.yaml @@ -101,13 +101,14 @@ services: PHOTOPRISM_HTTP_HOST: "0.0.0.0" PHOTOPRISM_HTTP_PORT: 2342 PHOTOPRISM_HTTP_COMPRESSION: "zstd,gzip" # improves transfer speed and bandwidth utilization (none, gzip, zstd, or comma-separated list e.g. "zstd,gzip") + MYSQL_TCP_PORT: "${MARIADB_PORT:-4001}" # default port used by the "mariadb" client (see .my.cnf) PHOTOPRISM_DATABASE_DRIVER: "mysql" - PHOTOPRISM_DATABASE_SERVER: "mariadb:4001" + PHOTOPRISM_DATABASE_SERVER: "mariadb:${MARIADB_PORT:-4001}" PHOTOPRISM_DATABASE_NAME: "photoprism" PHOTOPRISM_DATABASE_USER: "root" PHOTOPRISM_DATABASE_PASSWORD: "photoprism" PHOTOPRISM_TEST_DRIVER: "sqlite" - # PHOTOPRISM_TEST_DSN_MYSQL8: "root:photoprism@tcp(mysql:4001)/photoprism?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true&timeout=15s" + # PHOTOPRISM_TEST_DSN_MYSQL8: "root:photoprism@tcp(mysql:${MARIADB_PORT:-4001})/photoprism?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true&timeout=15s" PHOTOPRISM_ASSETS_PATH: "/go/src/github.com/photoprism/photoprism/assets" PHOTOPRISM_STORAGE_PATH: "/go/src/github.com/photoprism/photoprism/storage" PHOTOPRISM_ORIGINALS_PATH: "/go/src/github.com/photoprism/photoprism/storage/originals" @@ -186,12 +187,21 @@ services: security_opt: # see https://github.com/MariaDB/mariadb-docker/issues/434#issuecomment-1136151239 - seccomp:unconfined - apparmor:unconfined - command: --port=4001 --innodb-strict-mode=1 --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 + command: + - "--port=${MARIADB_PORT:-4001}" + - --innodb-strict-mode=1 + - --innodb-buffer-pool-size=256M + - --transaction-isolation=READ-COMMITTED + - --character-set-server=utf8mb4 + - --collation-server=utf8mb4_unicode_ci + - --max-connections=512 + - --innodb-rollback-on-timeout=OFF + - --innodb-lock-wait-timeout=120 expose: - - "4001" # 3306 isn't used intentionally to avoid conflicts and confuse port scanners + - "${MARIADB_PORT:-4001}" # does not default to 3306 in order to avoid conflicts and confuse port scanners ## Publish the MariaDB port on the host for direct access from the host: ports: - - "${SERVICES_BIND_HOST:-127.0.0.1}:4001:4001" # MariaDB + - "${SERVICES_BIND_HOST:-127.0.0.1}:${MARIADB_PORT:-4001}:${MARIADB_PORT:-4001}" # MariaDB volumes: - "mariadb:/var/lib/mysql" - "./scripts/sql/mariadb-init.sql:/docker-entrypoint-initdb.d/init.sql" @@ -209,10 +219,10 @@ services: postgres: image: postgres:18-alpine expose: - - "5432" + - "${POSTGRES_PORT:-5432}" ## Publish the PostgreSQL port on the host for direct access from the host: ports: - - "${SERVICES_BIND_HOST:-127.0.0.1}:5432:5432" # PostgreSQL + - "${SERVICES_BIND_HOST:-127.0.0.1}:${POSTGRES_PORT:-5432}:${POSTGRES_PORT:-5432}" # PostgreSQL volumes: - "postgres:/var/lib/postgresql" - "./scripts/sql/postgresql-init.sql:/docker-entrypoint-initdb.d/init.sql" @@ -220,6 +230,7 @@ services: POSTGRES_DB: photoprism POSTGRES_USER: photoprism POSTGRES_PASSWORD: photoprism + PGPORT: "${POSTGRES_PORT:-5432}" PGDATA: /var/lib/postgresql/18/docker ## Qdrant (Vector Database) @@ -449,7 +460,7 @@ services: KC_HOSTNAME_STRICT: "false" KC_PROXY: "edge" KC_DB: "mariadb" - KC_DB_URL: "jdbc:mariadb://mariadb:4001/keycloak" + KC_DB_URL: "jdbc:mariadb://mariadb:${MARIADB_PORT:-4001}/keycloak" KC_DB_USERNAME: "keycloak" KC_DB_PASSWORD: "keycloak" diff --git a/internal/config/test.go b/internal/config/test.go index 0f4075118..f1e156cc9 100644 --- a/internal/config/test.go +++ b/internal/config/test.go @@ -119,7 +119,8 @@ func NewTestOptionsForPath(dbName, dataPath string) *Options { // Obtain test database credentials. // - // Example PHOTOPRISM_TEST_DSN for MariaDB / MySQL: + // Example PHOTOPRISM_TEST_DSN for MariaDB / MySQL (the port matches the dev + // MariaDB service, which defaults to 4001 unless MARIADB_PORT overrides it): // - "photoprism:photoprism@tcp(mariadb:4001)/photoprism?parseTime=true" dbName = PkgNameRegexp.ReplaceAllString(dbName, "") testDriver := os.Getenv("PHOTOPRISM_TEST_DRIVER") diff --git a/internal/entity/migrate/dialect_mysql_test.go b/internal/entity/migrate/dialect_mysql_test.go index 665b3781d..c1fd01c12 100644 --- a/internal/entity/migrate/dialect_mysql_test.go +++ b/internal/entity/migrate/dialect_mysql_test.go @@ -1,6 +1,8 @@ package migrate import ( + "fmt" + "os" "os/exec" "path/filepath" "testing" @@ -28,9 +30,14 @@ func TestDialectMysql(t *testing.T) { log = logrus.StandardLogger() log.SetLevel(logrus.TraceLevel) + port := os.Getenv("MARIADB_PORT") + if port == "" { + port = "4001" + } + db, err := gorm.Open( "mysql", - "migrate:migrate@tcp(mariadb:4001)/migrate?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true", + fmt.Sprintf("migrate:migrate@tcp(mariadb:%s)/migrate?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true", port), ) if err != nil || db == nil { diff --git a/internal/service/cluster/provisioner/README.md b/internal/service/cluster/provisioner/README.md index 2f039e59f..19f42fa11 100644 --- a/internal/service/cluster/provisioner/README.md +++ b/internal/service/cluster/provisioner/README.md @@ -6,7 +6,7 @@ The provisioner package manages per-instance MariaDB schemas and users for clust ### Development Workflow -- Configuration lives in `database.go`. The admin connection string is `ProvisionDSN` (default `root:photoprism@tcp(mariadb:4001)/photoprism`). Query parameters are optional when configuring the portal flag/env (`database-provision-dsn`), for example `charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true&timeout=15s`. +- Configuration lives in `database.go`. The admin connection string is `ProvisionDSN`; the default targets the dev MariaDB service (`root:photoprism@tcp(mariadb:)/photoprism`) using the port from the `MARIADB_PORT` environment variable (falls back to `4001`). Query parameters are optional when configuring the portal flag/env (`database-provision-dsn`), for example `charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true&timeout=15s`. - `EnsureCredentials` accepts the technical node UUID/name identifiers, creates the schema if needed, and returns credentials plus rotation metadata. `DropCredentials` revokes grants, drops the user, and removes the schema. Both functions require a context; prefer `context.WithTimeout` in callers. - Identifier generation is centralized in `GenerateCredentials`. Call it instead of handcrafting database or user names so tests, CLI, and API stay aligned. The resulting identifiers follow `d` for schemas and `u` for users. Portal deployments may override the prefix via the `database-provision-prefix` flag; defaults are `cluster_d…` / `cluster_u…`. @@ -28,7 +28,7 @@ The provisioner package manages per-instance MariaDB schemas and users for clust ### MariaDB Troubleshooting -- Connect from the dev container using `mariadb` (already configured to reach `mariadb:4001`). Common snippets: +- Connect from the dev container using `mariadb` (configured via `.my.cnf` to reach the dev MariaDB service; the default port is `4001` unless `MARIADB_PORT` overrides it in `.env`). Common snippets: ```bash cat <<'SQL' | mariadb SHOW DATABASES LIKE 'cluster_d%'; -- adjust prefix if database-provision-prefix overrides the default diff --git a/internal/service/cluster/provisioner/database.go b/internal/service/cluster/provisioner/database.go index feb1cfee4..899869bdf 100644 --- a/internal/service/cluster/provisioner/database.go +++ b/internal/service/cluster/provisioner/database.go @@ -5,7 +5,9 @@ import ( "database/sql" "errors" "fmt" + "os" "regexp" + "strconv" "strings" "sync" "time" @@ -13,15 +15,26 @@ import ( _ "github.com/go-sql-driver/mysql" // register MySQL driver ) +// devDatabasePort returns the dev MariaDB port, honoring MARIADB_PORT when set so +// the provisioner stays aligned with compose.yaml overrides. +func devDatabasePort() int { + if v := os.Getenv("MARIADB_PORT"); v != "" { + if n, err := strconv.Atoi(v); err == nil && n > 0 && n < 65536 { + return n + } + } + return 4001 +} + // ProvisionDSN specifies the admin DSN used for auto-provisioning, for example: // root:insecure@tcp(127.0.0.1:3306)/photoprism?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true -var ProvisionDSN = "root:photoprism@tcp(mariadb:4001)/photoprism?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true" +var ProvisionDSN = fmt.Sprintf("root:photoprism@tcp(mariadb:%d)/photoprism?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true", devDatabasePort()) // DatabaseHost is the hostname of the admin server used for provisioning operations. var DatabaseHost = "mariadb" // DatabasePort is the port of the admin server used for provisioning operations. -var DatabasePort = 4001 +var DatabasePort = devDatabasePort() // DatabaseDriver indicates the SQL driver used for provisioning (independent from the app DB driver). var DatabaseDriver = "mysql" diff --git a/internal/service/cluster/provisioner/database_test.go b/internal/service/cluster/provisioner/database_test.go index 002413f5e..3ecd8cef7 100644 --- a/internal/service/cluster/provisioner/database_test.go +++ b/internal/service/cluster/provisioner/database_test.go @@ -11,6 +11,29 @@ import ( "github.com/stretchr/testify/assert" ) +// --- devDatabasePort --------------------------------------------------------- + +func TestDevDatabasePort(t *testing.T) { + t.Run("Default", func(t *testing.T) { + t.Setenv("MARIADB_PORT", "") + assert.Equal(t, 4001, devDatabasePort()) + }) + t.Run("Override", func(t *testing.T) { + t.Setenv("MARIADB_PORT", "4002") + assert.Equal(t, 4002, devDatabasePort()) + }) + t.Run("InvalidNonNumeric", func(t *testing.T) { + t.Setenv("MARIADB_PORT", "not-a-port") + assert.Equal(t, 4001, devDatabasePort()) + }) + t.Run("InvalidOutOfRange", func(t *testing.T) { + t.Setenv("MARIADB_PORT", "0") + assert.Equal(t, 4001, devDatabasePort()) + t.Setenv("MARIADB_PORT", "70000") + assert.Equal(t, 4001, devDatabasePort()) + }) +} + // --- Quoting helpers --------------------------------------------------------- func TestQuoteIdent_Valid(t *testing.T) {