From 052bd6635f2f0934f0f268b7a08b938d312a7e2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20G=C3=BCnther?= Date: Thu, 30 Nov 2023 12:02:58 +0100 Subject: [PATCH 1/2] Allow customization of the production database.yml --- config/database.production.yml | 77 +++++++++++++++++++ docker/prod/Dockerfile | 1 + docker/prod/setup/postinstall-common.sh | 8 -- .../configuration/database/README.md | 44 ++++++++++- 4 files changed, 121 insertions(+), 9 deletions(-) create mode 100644 config/database.production.yml diff --git a/config/database.production.yml b/config/database.production.yml new file mode 100644 index 000000000000..bcda2d54178b --- /dev/null +++ b/config/database.production.yml @@ -0,0 +1,77 @@ +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2023 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +<% +DATABASE_OPTIONS = %w[ + url + database + encoding + pool + username + password + sslmode + sslcompression + sslcert + sslkey + sslpassword + sslrootcert + sslcrl + application_name + statement_timeout +].freeze + +DATABASE_VARIABLES = %w[ + statement_timeout +] + +DATABASE_DEFAULTS = { + # Fallback to unprefixed DATABASE_URL if present + 'url' => ENV['DATABASE_URL'], + 'statement_timeout' => ENV.fetch("POSTGRES_STATEMENT_TIMEOUT", "90s"), + 'encoding' => 'unicode', + 'application_name' => 'openproject', +}.freeze +%> + +production: + adapter: postgresql + <% DATABASE_OPTIONS.each do |option| %> + <% env_name = "OPENPROJECT_DB_#{option.upcase}" %> + <% value = ENV.fetch(env_name, DATABASE_DEFAULTS[option]) %> + <% unless value.nil? %> + <%= option %>: <%= value %> + <% end %> + <% end %> + variables: + <% DATABASE_VARIABLES.each do |option| %> + <% env_name = "OPENPROJECT_DB_#{option.upcase}" %> + <% value = ENV.fetch(env_name, DATABASE_DEFAULTS[option]) %> + <% unless value.nil? %> + <%= option %>: <%= value %> + <% end %> + <% end %> diff --git a/docker/prod/Dockerfile b/docker/prod/Dockerfile index c54465e97ba8..a66bbd67c358 100644 --- a/docker/prod/Dockerfile +++ b/docker/prod/Dockerfile @@ -49,6 +49,7 @@ COPY Rakefile . COPY bin ./bin COPY app ./app COPY config ./config +COPY config/database.production.yml ./config/database.yml COPY lib ./lib COPY lib_static ./lib_static COPY frontend ./frontend diff --git a/docker/prod/setup/postinstall-common.sh b/docker/prod/setup/postinstall-common.sh index c2e5b7288ff5..ead33f2ff9c3 100755 --- a/docker/prod/setup/postinstall-common.sh +++ b/docker/prod/setup/postinstall-common.sh @@ -48,11 +48,3 @@ rm -rf "$APP_PATH/frontend/.angular" rm -rf /root/.npm rm -f "$APP_PATH/log/production.log" - -cat > "$APP_PATH/config/database.yml" < - variables: - # https://github.com/ankane/the-ultimate-guide-to-ruby-timeouts#postgresql - statement_timeout: <%= ENV.fetch("POSTGRES_STATEMENT_TIMEOUT", "90s") %> -CONF diff --git a/docs/installation-and-operations/configuration/database/README.md b/docs/installation-and-operations/configuration/database/README.md index d98f8244417f..799a124ced57 100644 --- a/docs/installation-and-operations/configuration/database/README.md +++ b/docs/installation-and-operations/configuration/database/README.md @@ -48,16 +48,58 @@ In both cases the seeder will be run when you (re)launch OpenProject to make sur +## Setting DATABASE_URL and options separately + +OpenProject will merge the settings from `DATABASE_URL` with manually specified environment options. Here are the supported options: + +| Environment variable | Default | Description | Documentation | +| ------------------------------------ | ----------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| DATABASE_URL
OPENPROJECT_DB_URL | *none* | URL style passing of database options | https://guides.rubyonrails.org/configuring.html#configuring-a-database | +| OPENPROJECT_DB_ENCODING | unicode | Encoding of the database | Should be left at unicode unless you really know what you're doing. | +| OPENPROJECT_DB_POOL | *none* | Connection pool count | https://guides.rubyonrails.org/configuring.html#database-pooling | +| OPENPROJECT_DB_USERNAME | *none* | Database username, if not presented in URL above | https://guides.rubyonrails.org/configuring.html#configuring-a-database | +| OPENPROJECT_DB_PASSWORD | *none* | Database password, if not presented in URL above | https://guides.rubyonrails.org/configuring.html#configuring-a-database | +| OPENPROJECT_DB_APPLICATION_NAME | openproject | PostgreSQL application name option | https://www.postgresql.org/docs/13/libpq-connect.html#LIBPQ-CONNECT-APPLICATION-NAME | +| OPENPROJECT_DB_STATEMENT_TIMEOUT | 90s | Default statement timeout before connection statements are terminted | https://www.postgresql.org/docs/current/runtime-config-client.html#GUC-STATEMENT-TIMEOUT | + + + ## Using SSL/TLS with a PostgreSQL database By default, the packaged installation installs a local database and does not use SSL encryption. If you provide a custom PostgreSQL database that supports SSL/TLS connections for servers and/or clients, you can pass the options as part of the DATABASE_URL. See the above guides on how to set this environment variable for Docker or packaged installations. -The most import option is the `sslmode` parameter. Set this to the appropriate mode as defined in the [PostgreSQL documentation](https://www.postgresql.org/docs/13/libpq-connect.html#LIBPQ-PARAMKEYWORDS). For example, to require a SSL connection with full verification of the server certificate, use these parameters: +The most import option is the `sslmode` parameter. Set this to the appropriate mode as defined in the [PostgreSQL documentation](https://www.postgresql.org/docs/13/libpq-connect.html#LIBPQ-PARAMKEYWORDS). For example, to require a SSL connection with full verification of the server certificate, you can add it to the database URL: ```bash DATABASE_URL=postgres://user:pass@host:port/dbname?sslmode=require-full&sslcert=/path/to/postgresql.cert ``` +Alternatively, for better readibility, you can set these parameters with separate environment variables: + +| Environment variable | Default | Description | PostgreSQL documentation | +| ----------------------------- | ---------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| OPENPROJECT_DB_SSLMODE | prefer | connection mode for SSL. See | [sslmode](https://www.postgresql.org/docs/13/libpq-connect.html#LIBPQ-CONNECT-SSLMODE) | +| OPENPROJECT_DB_SSLCOMPRESSION | 0 | If set to 1, data sent over SSL connections will be compressed | [sslcompression](https://www.postgresql.org/docs/13/libpq-connect.html#LIBPQ-CONNECT-SSLCOMPRESSION) | +| OPENPROJECT_DB_SSLCERT | ~/.postgresql/postgresql.crt | Path to certificate | [sslcert](https://www.postgresql.org/docs/13/libpq-connect.html#LIBPQ-CONNECT-SSLCERT) | +| OPENPROJECT_DB_SSLKEY | ~/.postgresql/postgresql.key | Path to certificate key | [sslkey](https://www.postgresql.org/docs/13/libpq-connect.html#LIBPQ-CONNECT-SSLKEY) | +| OPENPROJECT_DB_SSLPASSWORD | | Password to certificate key | [sslpassword](https://www.postgresql.org/docs/13/libpq-connect.html#LIBPQ-CONNECT-SSLPASSWORD) | +| OPENPROJECT_DB_SSLROOTCERT | ~/.postgresql/root.crt | Path to CA | [sslrootcert](https://www.postgresql.org/docs/13/libpq-connect.html#LIBPQ-CONNECT-SSLROOTCERT) | +| OPENPROJECT_DB_SSLCRL | ~/.postgresql/root.crl | Path to revocation list | [sslcrl](https://www.postgresql.org/docs/13/libpq-connect.html#LIBPQ-CONNECT-SSLCRL) | + + + +``` +="prefer" # disable, allow, prefer, require, verify-ca, verify-full +="0" # 0 or 1 +="~/.postgresql/postgresql.crt" # Path to the certificate +="~/.postgresql/postgresql.key" # Path to the certificate private key +="" # Password for the certificate key, if any +="~/.postgresql/root.crt" # Path to CA +="~/.postgresql/root.crl" # Path to revocation list +``` + + + PostgreSQL supports a wide variety of options in its connection string. This is not specific to OpenProject or Rails. See the following guide for more information: https://www.postgresql.org/docs/13/libpq-connect.html#LIBPQ-PARAMKEYWORDS From 69747f21df75e439ec1aa63d5a904d91e229cb3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20G=C3=BCnther?= Date: Thu, 30 Nov 2023 13:42:30 +0100 Subject: [PATCH 2/2] Replace packager database.yml with it --- packaging/conf/database.yml | 14 -------------- packaging/setup | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) delete mode 100644 packaging/conf/database.yml diff --git a/packaging/conf/database.yml b/packaging/conf/database.yml deleted file mode 100644 index a5a26d84ffe5..000000000000 --- a/packaging/conf/database.yml +++ /dev/null @@ -1,14 +0,0 @@ -<% url = ENV.fetch('DATABASE_URL') %> -production: - url: <%= url %> - <% if encoding = ENV['DATABASE_ENCODING'] %> - encoding: '<%= encoding %>' - <% end %> - <% if url.start_with? 'mysql' %> - reconnect: true - variables: - # These are the default MySql Modes for rails 5.0 only excluding - # ONLY_FULL_GROUP_BY which would interfere with the current implementation - # of the query grouping by custom fields. - sql_mode: "no_auto_value_on_zero,strict_trans_tables,strict_all_tables,no_zero_in_date,no_zero_date,error_for_division_by_zero,no_engine_substitution" - <% end %> diff --git a/packaging/setup b/packaging/setup index be83296ce353..b4a1de34b335 100755 --- a/packaging/setup +++ b/packaging/setup @@ -4,7 +4,7 @@ date -u +"%Y-%m-%dT%H:%M:%SZ" > RELEASE_DATE # Copy default database.yml -cp -f packaging/conf/database.yml config/database.yml +cp -f config/database.production.yml config/database.yml cp -f packaging/conf/configuration.yml config/configuration.yml sed -i "s|config.public_file_server.enabled = false|config.public_file_server.enabled = true|" config/environments/production.rb