diff --git a/docs/docs/install/environment-variables.md b/docs/docs/install/environment-variables.md index e11547d240..c853a873ab 100644 --- a/docs/docs/install/environment-variables.md +++ b/docs/docs/install/environment-variables.md @@ -80,6 +80,7 @@ Information on the current workers can be found [here](/docs/administration/jobs | `DB_USERNAME` | Database user | `postgres` | server, database<sup>\*1</sup> | | `DB_PASSWORD` | Database password | `postgres` | server, database<sup>\*1</sup> | | `DB_DATABASE_NAME` | Database name | `immich` | server, database<sup>\*1</sup> | +| `DB_SSL_MODE` | Database SSL mode | | server | | `DB_VECTOR_EXTENSION`<sup>\*2</sup> | Database vector extension (one of [`pgvector`, `pgvecto.rs`]) | `pgvecto.rs` | server | | `DB_SKIP_MIGRATIONS` | Whether to skip running migrations on startup (one of [`true`, `false`]) | `false` | server | diff --git a/server/src/dtos/env.dto.ts b/server/src/dtos/env.dto.ts index 6c238252a6..7f0df8abb9 100644 --- a/server/src/dtos/env.dto.ts +++ b/server/src/dtos/env.dto.ts @@ -1,6 +1,6 @@ import { Transform, Type } from 'class-transformer'; import { IsEnum, IsInt, IsString } from 'class-validator'; -import { ImmichEnvironment, LogLevel } from 'src/enum'; +import { DatabaseSslMode, ImmichEnvironment, LogLevel } from 'src/enum'; import { IsIPRange, Optional, ValidateBoolean } from 'src/validation'; export class EnvDto { @@ -142,6 +142,10 @@ export class EnvDto { @ValidateBoolean({ optional: true }) DB_SKIP_MIGRATIONS?: boolean; + @IsEnum(DatabaseSslMode) + @Optional() + DB_SSL_MODE?: DatabaseSslMode; + @IsString() @Optional() DB_URL?: string; diff --git a/server/src/enum.ts b/server/src/enum.ts index 4e725e1c13..a9ea285c24 100644 --- a/server/src/enum.ts +++ b/server/src/enum.ts @@ -610,3 +610,11 @@ export enum OAuthTokenEndpointAuthMethod { CLIENT_SECRET_POST = 'client_secret_post', CLIENT_SECRET_BASIC = 'client_secret_basic', } + +export enum DatabaseSslMode { + Disable = 'disable', + Allow = 'allow', + Prefer = 'prefer', + Require = 'require', + VerifyFull = 'verify-full', +} diff --git a/server/src/repositories/config.repository.spec.ts b/server/src/repositories/config.repository.spec.ts index 9e9ed71191..143892fdd0 100644 --- a/server/src/repositories/config.repository.spec.ts +++ b/server/src/repositories/config.repository.spec.ts @@ -23,6 +23,7 @@ const resetEnv = () => { 'DB_USERNAME', 'DB_PASSWORD', 'DB_DATABASE_NAME', + 'DB_SSL_MODE', 'DB_SKIP_MIGRATIONS', 'DB_VECTOR_EXTENSION', @@ -92,6 +93,17 @@ describe('getEnv', () => { }); }); + it('should validate DB_SSL_MODE', () => { + process.env.DB_SSL_MODE = 'invalid'; + expect(() => getEnv()).toThrowError('Invalid environment variables: DB_SSL_MODE'); + }); + + it('should accept a valid DB_SSL_MODE', () => { + process.env.DB_SSL_MODE = 'prefer'; + const { database } = getEnv(); + expect(database.config).toMatchObject(expect.objectContaining({ ssl: 'prefer' })); + }); + it('should allow skipping migrations', () => { process.env.DB_SKIP_MIGRATIONS = 'true'; const { database } = getEnv(); diff --git a/server/src/repositories/config.repository.ts b/server/src/repositories/config.repository.ts index 9b88a78e6b..9b3e406437 100644 --- a/server/src/repositories/config.repository.ts +++ b/server/src/repositories/config.repository.ts @@ -193,6 +193,7 @@ const getEnv = (): EnvData => { username: dto.DB_USERNAME || 'postgres', password: dto.DB_PASSWORD || 'postgres', database: dto.DB_DATABASE_NAME || 'immich', + ssl: dto.DB_SSL_MODE || undefined, }; return { diff --git a/server/src/types.ts b/server/src/types.ts index d18ef297ef..2f5bfad02c 100644 --- a/server/src/types.ts +++ b/server/src/types.ts @@ -2,6 +2,7 @@ import { SystemConfig } from 'src/config'; import { AssetType, DatabaseExtension, + DatabaseSslMode, ExifOrientation, ImageFormat, JobName, @@ -380,6 +381,7 @@ export type DatabaseConnectionParts = { username: string; password: string; database: string; + ssl?: DatabaseSslMode; }; export type DatabaseConnectionParams = DatabaseConnectionURL | DatabaseConnectionParts; diff --git a/server/src/utils/database.ts b/server/src/utils/database.ts index b44ea5da46..985605eb07 100644 --- a/server/src/utils/database.ts +++ b/server/src/utils/database.ts @@ -17,7 +17,7 @@ import { parse } from 'pg-connection-string'; import postgres, { Notice } from 'postgres'; import { columns, Exif, Person } from 'src/database'; import { DB } from 'src/db'; -import { AssetFileType, DatabaseExtension } from 'src/enum'; +import { AssetFileType, DatabaseExtension, DatabaseSslMode } from 'src/enum'; import { TimeBucketSize } from 'src/repositories/asset.repository'; import { AssetSearchBuilderOptions } from 'src/repositories/search.repository'; import { DatabaseConnectionParams, VectorExtension } from 'src/types'; @@ -35,7 +35,7 @@ export const asPostgresConnectionConfig = (params: DatabaseConnectionParams) => username: params.username, password: params.password, database: params.database, - ssl: undefined, + ssl: params.ssl === DatabaseSslMode.Disable ? false : params.ssl, }; }