diff --git a/backend/config/default.json b/backend/config/default.json index 154e66e489..8654b4cfff 100644 --- a/backend/config/default.json +++ b/backend/config/default.json @@ -2,9 +2,9 @@ "database": { "engine": "mysql2", "host": "db", + "port": 3306, "name": "npm", "user": "npm", - "password": "npm", - "port": 3306 + "password": "npm" } } diff --git a/backend/lib/config.js b/backend/lib/config.js index 7d20fd02d3..c17f62f720 100644 --- a/backend/lib/config.js +++ b/backend/lib/config.js @@ -5,14 +5,38 @@ import { global as logger } from "../logger.js"; const keysFile = '/data/keys.json'; const mysqlEngine = 'mysql2'; const postgresEngine = 'pg'; +const sqliteEngine = 'knex-native'; const sqliteClientName = 'sqlite3'; +const dataBaseEngines = { + mysql: { + engine: mysqlEngine, + host: '127.0.0.1', + port: 3306, + }, + mariadb: { + engine: mysqlEngine, + host: '127.0.0.1', + port: 3306, + }, + postgres: { + engine: postgresEngine, + host: '127.0.0.1', + port: 5432, + }, + sqlite: { + engine: sqliteEngine, + }, +}; + let instance = null; // 1. Load from config file first (not recommended anymore) // 2. Use config env variables next const configure = () => { const filename = `${process.env.NODE_CONFIG_DIR || "./config"}/${process.env.NODE_ENV || "default"}.json`; + const toBool = (v) => /^(1|true|yes|on)$/i.test((v || '').trim()); + if (fs.existsSync(filename)) { let configData; try { @@ -37,15 +61,70 @@ const configure = () => { } } - const toBool = (v) => /^(1|true|yes|on)$/i.test((v || '').trim()); + const envDataBaseEngne = process.env.DB_ENGINE || null; + if (envDataBaseEngne) { + if (envDataBaseEngne === 'sqlite') { + const defaultConection = dataBaseEngines[envDataBaseEngne]; + const sqliteEnvFile = process.env.DB_SQLITE_FILE || '/data/database.sqlite'; + logger.info(`Using Sqlite: ${sqliteEnvFile}`); + instance = { + database: { + engine: defaultConection.engine, + knex: { + client: sqliteClientName, + connection: { + filename: sqliteEnvFile + }, + useNullAsDefault: true + } + }, + keys: getKeys(), + }; + } else if (envDataBaseEngne === 'mysql' || envDataBaseEngne === 'mariadb') { + logger.info(`Using ${envDataBaseEngne} configuration`); + const defaultConection = dataBaseEngines[envDataBaseEngne]; + const envMysqlSSL = toBool(process.env.DB_MYSQL_SSL); + const envMysqlSSLRejectUnauthorized = process.env.DB_MYSQL_SSL_REJECT_UNAUTHORIZED === undefined ? true : toBool(process.env.DB_MYSQL_SSL_REJECT_UNAUTHORIZED); + const envMysqlSSLVerifyIdentity = process.env.DB_MYSQL_SSL_VERIFY_IDENTITY === undefined ? true : toBool(process.env.DB_MYSQL_SSL_VERIFY_IDENTITY); + instance = { + database: { + engine: defaultConection.engine, + host: process.env.DB_HOST || defaultConection.host, + port: process.env.DB_PORT || defaultConection.port, + name: process.env.DB_NAME || 'npm', + user: process.env.DB_USER || 'npm', + password: process.env.DB_PASSWORD || 'npmpass', + ssl: envMysqlSSL ? { rejectUnauthorized: envMysqlSSLRejectUnauthorized, verifyIdentity: envMysqlSSLVerifyIdentity } : false, + }, + keys: getKeys(), + }; + } else { + // we have enough mysql/mariadb/postgres creds to go with mysql/mariadb/postgres + logger.info(`Using ${envDataBaseEngne} configuration`); + const defaultConection = dataBaseEngines[envDataBaseEngne]; + instance = { + database: { + engine: defaultConection.engine, + host: process.env.DB_HOST || defaultConection.host, + port: process.env.DB_PORT || defaultConection.port, + name: process.env.DB_NAME || 'npm', + user: process.env.DB_USER || 'npm', + password: process.env.DB_PASSWORD || 'npmpass', + }, + keys: getKeys(), + }; + } + return; + } - const envMysqlHost = process.env.DB_MYSQL_HOST || null; - const envMysqlUser = process.env.DB_MYSQL_USER || null; - const envMysqlName = process.env.DB_MYSQL_NAME || null; - const envMysqlSSL = toBool(process.env.DB_MYSQL_SSL); - const envMysqlSSLRejectUnauthorized = process.env.DB_MYSQL_SSL_REJECT_UNAUTHORIZED === undefined ? true : toBool(process.env.DB_MYSQL_SSL_REJECT_UNAUTHORIZED); - const envMysqlSSLVerifyIdentity = process.env.DB_MYSQL_SSL_VERIFY_IDENTITY === undefined ? true : toBool(process.env.DB_MYSQL_SSL_VERIFY_IDENTITY); + // TODO: Remove this section in future versions; it is retained for backward compatibility. + const envMysqlHost = process.env.DB_MYSQL_HOST || null; + const envMysqlUser = process.env.DB_MYSQL_USER || null; + const envMysqlName = process.env.DB_MYSQL_NAME || null; if (envMysqlHost && envMysqlUser && envMysqlName) { + const envMysqlSSL = toBool(process.env.DB_MYSQL_SSL); + const envMysqlSSLRejectUnauthorized = process.env.DB_MYSQL_SSL_REJECT_UNAUTHORIZED === undefined ? true : toBool(process.env.DB_MYSQL_SSL_REJECT_UNAUTHORIZED); + const envMysqlSSLVerifyIdentity = process.env.DB_MYSQL_SSL_VERIFY_IDENTITY === undefined ? true : toBool(process.env.DB_MYSQL_SSL_VERIFY_IDENTITY); // we have enough mysql creds to go with mysql logger.info("Using MySQL configuration"); instance = { @@ -63,6 +142,7 @@ const configure = () => { return; } + // TODO: Remove this section in future versions; it is retained for backward compatibility. const envPostgresHost = process.env.DB_POSTGRES_HOST || null; const envPostgresUser = process.env.DB_POSTGRES_USER || null; const envPostgresName = process.env.DB_POSTGRES_NAME || null; @@ -87,9 +167,9 @@ const configure = () => { logger.info(`Using Sqlite: ${envSqliteFile}`); instance = { database: { - engine: "knex-native", - knex: { - client: sqliteClientName, + engine: sqliteEngine, + knex: { + client: sqliteClientName, connection: { filename: envSqliteFile, }, diff --git a/docker/docker-compose.ci.mysql.yml b/docker/docker-compose.ci.mysql.yml index 108a1dca3d..427ebd9a4e 100644 --- a/docker/docker-compose.ci.mysql.yml +++ b/docker/docker-compose.ci.mysql.yml @@ -3,11 +3,12 @@ services: fullstack: environment: - DB_MYSQL_HOST: 'db-mysql' - DB_MYSQL_PORT: '3306' - DB_MYSQL_USER: 'npm' - DB_MYSQL_PASSWORD: 'npmpass' - DB_MYSQL_NAME: 'npm' + DB_ENGINE: 'mysql' + DB_HOST: 'db-mysql' + DB_PORT: '3306' + DB_NAME: 'npm' + DB_USER: 'npm' + DB_PASSWORD: 'npmpass' depends_on: - db-mysql diff --git a/docker/docker-compose.ci.postgres.yml b/docker/docker-compose.ci.postgres.yml index e9eb4bc2c6..70b7681bb8 100644 --- a/docker/docker-compose.ci.postgres.yml +++ b/docker/docker-compose.ci.postgres.yml @@ -6,11 +6,12 @@ services: fullstack: environment: - DB_POSTGRES_HOST: "db-postgres" - DB_POSTGRES_PORT: "5432" - DB_POSTGRES_USER: "npm" - DB_POSTGRES_PASSWORD: "npmpass" - DB_POSTGRES_NAME: "npm" + DB_ENGINE: "postgres" + DB_HOST: "db-postgres" + DB_PORT: "5432" + DB_NAME: "npm" + DB_USER: "npm" + DB_PASSWORD: "npmpass" depends_on: - db-postgres - authentik diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 57c30e073c..62ecfc2d6a 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -26,17 +26,20 @@ services: DEVELOPMENT: "true" LE_STAGING: "true" # db: - # DB_MYSQL_HOST: 'db' - # DB_MYSQL_PORT: '3306' - # DB_MYSQL_USER: 'npm' - # DB_MYSQL_PASSWORD: 'npm' - # DB_MYSQL_NAME: 'npm' + # DB_ENGINE: 'mysql' + # DB_HOST: 'db' + # DB_PORT: '3306' + # DB_NAME: 'npm' + # DB_USER: 'npm' + # DB_PASSWORD: 'npmpass' # db-postgres: - DB_POSTGRES_HOST: "db-postgres" - DB_POSTGRES_PORT: "5432" - DB_POSTGRES_USER: "npm" - DB_POSTGRES_PASSWORD: "npmpass" - DB_POSTGRES_NAME: "npm" + DB_ENGINE: "postgres" + DB_HOST: "db-postgres" + DB_PORT: "5432" + DB_NAME: "npm" + DB_USER: "npm" + DB_PASSWORD: "npmpass" + # DB_ENGINE: 'sqlite' # DB_SQLITE_FILE: "/data/database.sqlite" # DISABLE_IPV6: "true" # Required for DNS Certificate provisioning testing: @@ -70,10 +73,10 @@ services: - nginx_proxy_manager environment: TZ: "${TZ:-Australia/Brisbane}" - MYSQL_ROOT_PASSWORD: "npm" - MYSQL_DATABASE: "npm" - MYSQL_USER: "npm" - MYSQL_PASSWORD: "npm" + MYSQL_ROOT_PASSWORD: 'npm' + MYSQL_DATABASE: 'npm' + MYSQL_USER: 'npm' + MYSQL_PASSWORD: 'npm' volumes: - db_data:/var/lib/mysql - "/etc/localtime:/etc/localtime:ro" diff --git a/docs/src/advanced-config/index.md b/docs/src/advanced-config/index.md index e4a9594e0e..014cc0abc7 100644 --- a/docs/src/advanced-config/index.md +++ b/docs/src/advanced-config/index.md @@ -112,12 +112,13 @@ services: - '81:81' environment: # These are the settings to access your db - DB_MYSQL_HOST: "db" - DB_MYSQL_PORT: 3306 - DB_MYSQL_USER: "npm" - # DB_MYSQL_PASSWORD: "npm" # use secret instead - DB_MYSQL_PASSWORD__FILE: /run/secrets/MYSQL_PWD - DB_MYSQL_NAME: "npm" + DB_ENGINE: "mysql" + DB_HOST: "db" + DB_PORT: 3306 + DB_NAME: "npm" + DB_USER: "npm" + # DB_PASSWORD: "npmpass" # use secret instead + DB_PASSWORD__FILE: /run/secrets/MYSQL_PWD # If you would rather use Sqlite, remove all DB_MYSQL_* lines above # Uncomment this if IPv6 is not enabled on your host # DISABLE_IPV6: 'true' @@ -137,7 +138,7 @@ services: MYSQL_ROOT_PASSWORD__FILE: /run/secrets/DB_ROOT_PWD MYSQL_DATABASE: "npm" MYSQL_USER: "npm" - # MYSQL_PASSWORD: "npm" # use secret instead + # MYSQL_PASSWORD: "npmpass" # use secret instead MYSQL_PASSWORD__FILE: /run/secrets/MYSQL_PWD MARIADB_AUTO_UPGRADE: '1' volumes: diff --git a/docs/src/setup/index.md b/docs/src/setup/index.md index 998508dddb..57ccf1108a 100644 --- a/docs/src/setup/index.md +++ b/docs/src/setup/index.md @@ -53,7 +53,7 @@ If you opt for the MySQL configuration you will have to provide the database ser It's easy to use another docker container for your database also and link it as part of the docker stack, so that's what the following examples are going to use. -Here is an example of what your `docker-compose.yml` will look like when using a MariaDB container: +Use `DB_ENGINE` environment variable with `mysql`/`mariadb` value, here is an example of what your `docker-compose.yml` will look like when using a MariaDB container: ```yml services: @@ -69,12 +69,13 @@ services: # - '21:21' # FTP environment: TZ: "Australia/Brisbane" - # Mysql/Maria connection parameters: - DB_MYSQL_HOST: "db" - DB_MYSQL_PORT: 3306 - DB_MYSQL_USER: "npm" - DB_MYSQL_PASSWORD: "npm" - DB_MYSQL_NAME: "npm" + # MySQL/MariaDB connection parameters: + DB_ENGINE: 'mysql' # It also works with `mariadb` + DB_HOST: "db" + DB_PORT: 3306 + DB_NAME: "npm" + DB_USER: "npm" + DB_PASSWORD: "npmpass" # Optional SSL (see section below) # DB_MYSQL_SSL: 'true' # DB_MYSQL_SSL_REJECT_UNAUTHORIZED: 'true' @@ -94,7 +95,7 @@ services: MYSQL_ROOT_PASSWORD: 'npm' MYSQL_DATABASE: 'npm' MYSQL_USER: 'npm' - MYSQL_PASSWORD: 'npm' + MYSQL_PASSWORD: 'npmpass' MARIADB_AUTO_UPGRADE: '1' volumes: - ./mysql:/var/lib/mysql @@ -118,7 +119,7 @@ Enabling SSL using a self-signed cert (not recommended for production). ## Using Postgres database -Similar to the MySQL server setup: +Use `DB_ENGINE` environment variable with `postgres` value, similar to the MySQL server setup: ```yml services: @@ -134,12 +135,13 @@ services: # - '21:21' # FTP environment: TZ: "Australia/Brisbane" - # Postgres parameters: - DB_POSTGRES_HOST: 'db' - DB_POSTGRES_PORT: '5432' - DB_POSTGRES_USER: 'npm' - DB_POSTGRES_PASSWORD: 'npmpass' - DB_POSTGRES_NAME: 'npm' + # PostgreSQL parameters: + DB_ENGINE: 'postgres' + DB_HOST: 'db' + DB_PORT: '5432' + DB_NAME: 'npm' + DB_USER: 'npm' + DB_PASSWORD: 'npmpass' # Uncomment this if IPv6 is not enabled on your host # DISABLE_IPV6: 'true' volumes: @@ -151,9 +153,9 @@ services: db: image: postgres:17 environment: + POSTGRES_DB: 'npm' POSTGRES_USER: 'npm' POSTGRES_PASSWORD: 'npmpass' - POSTGRES_DB: 'npm' volumes: - ./postgresql:/var/lib/postgresql ```