From aeb0f286bc9172d63e21b3943bc7fed1b50f8549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Sun, 21 Apr 2024 08:41:08 +0100 Subject: [PATCH 01/23] Create skeleton runtime config --- config/runtime.exs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/config/runtime.exs b/config/runtime.exs index e69de29bb..9ea71019f 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -0,0 +1,27 @@ +import Config + +# config/runtime.exs is executed for all environments, including +# during releases. It is executed after compilation and before the +# system starts, so it is typically used to load production configuration +# and secrets from environment variables or elsewhere. Do not define +# any compile-time configuration in here, as it won't be applied. +# The block below contains prod specific runtime configuration. + +# ## Using releases +# +# If you use `mix release`, you need to explicitly enable the server +# by passing the PHX_SERVER=true when you start it: +# +# PHX_SERVER=true bin/teiserver start +# +# Alternatively, you can use `mix phx.gen.release` to generate a `bin/server` +# script that automatically sets the env var above. +if System.get_env("PHX_SERVER") do + config :teiserver, TeiserverWeb.Endpoint, server: true +end + +# Only do some runtime configuration in production since in dev and tests the +# files are automatically recompiled on the fly and thus, config/{dev,test}.exs +# are just fine +if config_env() == :prod do +end From 4856e6f9584ab7d621ab3d3c594f18c91965dd66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Sun, 21 Apr 2024 08:51:27 +0100 Subject: [PATCH 02/23] Move setup key to runtime config --- config/runtime.exs | 7 +++++++ documents/guides/production_setup_linux.md | 2 +- documents/prod_files/example_prod_secret.exs | 3 --- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/config/runtime.exs b/config/runtime.exs index 9ea71019f..be826a6fd 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -24,4 +24,11 @@ end # files are automatically recompiled on the fly and thus, config/{dev,test}.exs # are just fine if config_env() == :prod do + + # this is used in lib/teiserver_web/controllers/account/setup_controller.ex + # as a special endpoint to create the root user. Setting it to empty or nil + # will disable the functionality completely. + # There is already a root user, so disable it + config :teiserver, Teiserver.Setup, key: nil + end diff --git a/documents/guides/production_setup_linux.md b/documents/guides/production_setup_linux.md index 3836bde14..660609d94 100644 --- a/documents/guides/production_setup_linux.md +++ b/documents/guides/production_setup_linux.md @@ -341,7 +341,7 @@ tsapp eval "Teiserver.Release.migrate" [Deployment itself is located in a different file.](/documents/guides/deployment.md), you will need to execute a deployment as part of the setup. There will be additional steps to take after your first deployment. #### Creating the first user -To create your first root user make a note of `config :teiserver, Teiserver.Setup, key:` within `config/prod.secret.exs` as you will need that value here. Go to `https://domain.com/initial_setup/$KEY` where `$KEY` is replaced with the value in this config. This link will only work while a user with an email "root@localhost" has not been created. It is advised that once the user is created you set the initial_setup key to be an empty string which will disable the function entirely. +To create your first root user make a note of `config :teiserver, Teiserver.Setup, key:` within `config/runtime.exs` as you will need that value here. Go to `https://domain.com/initial_setup/$KEY` where `$KEY` is replaced with the value in this config. This link will only work while a user with an email "root@localhost" has not been created. It is advised that once the user is created you set the initial_setup key to be an empty string which will disable the function entirely. A new user with developer level access will be created with the email `root@localhost` and a password identical to the setup key you just used. You can now login as that user, it is advised your first action should be to change/update the password and set the user details (name/email) to the ones you intend to use as admin. diff --git a/documents/prod_files/example_prod_secret.exs b/documents/prod_files/example_prod_secret.exs index 7fe3d76b2..2d72aef29 100644 --- a/documents/prod_files/example_prod_secret.exs +++ b/documents/prod_files/example_prod_secret.exs @@ -6,9 +6,6 @@ import Config secret_key_base = "mix phx.gen.secret" -config :teiserver, Teiserver.Setup, - key: "---- random string of alpha numeric characters ----" - # This can be part of your standard prod.exs but I wanted it to # default to not going into a github repo config :teiserver, TeiserverWeb.Endpoint, From fae24a8048c18a425b450cd2b3472fa218bd6600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Sun, 21 Apr 2024 08:55:33 +0100 Subject: [PATCH 03/23] Move Server TLS endpoint params to runtime config Leave the more static configuration like the list of cipher in the prod.exs file since these are unlikely to change any time soon. They can always be moved across if required. --- config/prod.exs | 6 ------ config/runtime.exs | 21 ++++++++++++++++++++ documents/prod_files/example_prod_secret.exs | 11 ---------- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/config/prod.exs b/config/prod.exs index 3c952f7d7..c1d95f6b4 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -14,11 +14,6 @@ config :teiserver, TeiserverWeb.Endpoint, https: [ port: 8888, otp_app: :teiserver, - keyfile: "/var/www/tls/privkey.pem", - certfile: "/var/www/tls/cert.pem", - cacertfile: "/var/www/tls/fullchain.pem", - versions: [:"tlsv1.2"], - dhfile: '/var/www/tls/dh-params.pem', ciphers: [ 'ECDHE-ECDSA-AES256-GCM-SHA384', 'ECDHE-RSA-AES256-GCM-SHA384', @@ -66,7 +61,6 @@ config :teiserver, TeiserverWeb.Endpoint, root: ".", cache_static_manifest: "priv/static/cache_manifest.json", server: true, - check_origin: ["//yourdomain.com", "//*.yourdomain.com"], version: Mix.Project.config()[:version] config :teiserver, Teiserver, diff --git a/config/runtime.exs b/config/runtime.exs index be826a6fd..e22ad7523 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -24,6 +24,14 @@ end # files are automatically recompiled on the fly and thus, config/{dev,test}.exs # are just fine if config_env() == :prod do + # used for mailing, checking origins, finding tls certs… + domain_name = System.get_env("DOMAIN_NAME", "beyondallreason.info") + + certificates = [ + keyfile: System.fetch_env!("TLS_PRIVATE_KEY_PATH"), + certfile: System.fetch_env!("TLS_CERT_PATH"), + cacertfile: System.fetch_env!("TLS_CA_CERT_PATH") + ] # this is used in lib/teiserver_web/controllers/account/setup_controller.ex # as a special endpoint to create the root user. Setting it to empty or nil @@ -31,4 +39,17 @@ if config_env() == :prod do # There is already a root user, so disable it config :teiserver, Teiserver.Setup, key: nil + config :teiserver, TeiserverWeb.Endpoint, + url: [host: domain_name], + check_origin: ["//#{domain_name}", "//*.#{domain_name}"], + https: + certificates ++ + [ + versions: [:"tlsv1.2"], + # dhfile is not supported for tls 1.3 + # https://www.erlang.org/doc/man/ssl.html#type-dh_file + dhfile: System.fetch_env!("TLS_DH_FILE_PATH") + ] + + end diff --git a/documents/prod_files/example_prod_secret.exs b/documents/prod_files/example_prod_secret.exs index 2d72aef29..96cc28428 100644 --- a/documents/prod_files/example_prod_secret.exs +++ b/documents/prod_files/example_prod_secret.exs @@ -6,17 +6,6 @@ import Config secret_key_base = "mix phx.gen.secret" -# This can be part of your standard prod.exs but I wanted it to -# default to not going into a github repo -config :teiserver, TeiserverWeb.Endpoint, - url: [host: "yourdomain.com"], - https: [ - keyfile: "/etc/letsencrypt/live/yourdomain.com/privkey.pem", - certfile: "/etc/letsencrypt/live/yourdomain.com/cert.pem", - cacertfile: "/etc/letsencrypt/live/yourdomain.com/fullchain.pem" - ], - check_origin: ["//yourdomain.com", "//*.yourdomain.com"] - config :teiserver, Teiserver, game_name: "My game name", game_name_short: "GN", From ee5974105aeb2d66fa3b30d4129f3837470622bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Sun, 21 Apr 2024 09:02:33 +0100 Subject: [PATCH 04/23] Move to runtime config the remaining endpoints config --- config/runtime.exs | 5 ++++- documents/prod_files/example_prod_secret.exs | 4 ---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/config/runtime.exs b/config/runtime.exs index e22ad7523..ea51dafec 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -49,7 +49,10 @@ if config_env() == :prod do # dhfile is not supported for tls 1.3 # https://www.erlang.org/doc/man/ssl.html#type-dh_file dhfile: System.fetch_env!("TLS_DH_FILE_PATH") - ] + ], + http: [:inet6, port: String.to_integer(System.get_env("PORT", "4000"))], + secret_key_base: System.fetch_env!("HTTP_SECRET_KEY_BASE") + end diff --git a/documents/prod_files/example_prod_secret.exs b/documents/prod_files/example_prod_secret.exs index 96cc28428..cd21882ed 100644 --- a/documents/prod_files/example_prod_secret.exs +++ b/documents/prod_files/example_prod_secret.exs @@ -25,10 +25,6 @@ config :teiserver, Teiserver.Repo, pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"), timeout: 30_000 -config :teiserver, TeiserverWeb.Endpoint, - http: [:inet6, port: String.to_integer(System.get_env("PORT") || "4000")], - secret_key_base: secret_key_base - config :teiserver, Teiserver.Account.Guardian, issuer: "teiserver", secret_key: "mix phx.gen.secret" From c91d760253b14515fe520b54965e8e9b7b2665ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Sun, 21 Apr 2024 09:03:49 +0100 Subject: [PATCH 05/23] General config to runtime config --- config/prod.exs | 11 ----------- config/runtime.exs | 12 ++++++++++++ documents/prod_files/example_prod_secret.exs | 12 ------------ 3 files changed, 12 insertions(+), 23 deletions(-) diff --git a/config/prod.exs b/config/prod.exs index c1d95f6b4..414a80b49 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -63,17 +63,6 @@ config :teiserver, TeiserverWeb.Endpoint, server: true, version: Mix.Project.config()[:version] -config :teiserver, Teiserver, - certs: [ - keyfile: "/var/www/tls/privkey.pem", - certfile: "/var/www/tls/cert.pem", - cacertfile: "/var/www/tls/fullchain.pem" - ], - enable_benchmark: false, - node_name: "node-name", - enable_managed_lobbies: true, - tachyon_schema_path: "/apps/teiserver/lib/teiserver-0.1.0/priv/tachyon/schema_v1/*/*/*.json" - config :teiserver, Teiserver.Repo, pool_size: String.to_integer(System.get_env("POOL_SIZE") || "40"), timeout: 120_000, diff --git a/config/runtime.exs b/config/runtime.exs index ea51dafec..4acfa8493 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -39,6 +39,18 @@ if config_env() == :prod do # There is already a root user, so disable it config :teiserver, Teiserver.Setup, key: nil + config :teiserver, Teiserver, + game_name: "Beyond all reason", + game_name_short: "BAR", + main_website: "https://www.beyondallreason.info/", + privacy_email: "privacy@beyondallreason.info", + discord: System.get_env("DISCORD_LINK"), + certs: certificates, + enable_benchmark: false, + node_name: System.fetch_env!("NODE_NAME"), + enable_managed_lobbies: true, + tachyon_schema_path: "/apps/teiserver/lib/teiserver-0.1.0/priv/tachyon/schema_v1/*/*/*.json" + config :teiserver, TeiserverWeb.Endpoint, url: [host: domain_name], check_origin: ["//#{domain_name}", "//*.#{domain_name}"], diff --git a/documents/prod_files/example_prod_secret.exs b/documents/prod_files/example_prod_secret.exs index cd21882ed..b48d1c5a5 100644 --- a/documents/prod_files/example_prod_secret.exs +++ b/documents/prod_files/example_prod_secret.exs @@ -6,18 +6,6 @@ import Config secret_key_base = "mix phx.gen.secret" -config :teiserver, Teiserver, - game_name: "My game name", - game_name_short: "GN", - main_website: "https://site.com", - privacy_email: "privacy@site.com", - discord: "My discord link"# Set to nil to not have link, - certs: [ - keyfile: "/etc/letsencrypt/live/yourdomain.com/privkey.pem", - certfile: "/etc/letsencrypt/live/yourdomain.com/cert.pem", - cacertfile: "/etc/letsencrypt/live/yourdomain.com/fullchain.pem" - ] - config :teiserver, Teiserver.Repo, username: "teiserver_prod", password: "mix phx.gen.secret", From c4eb48d530d26d84cf4be82e6d3e19de53c96259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Sun, 21 Apr 2024 09:04:57 +0100 Subject: [PATCH 06/23] Ecto repo config to runtime configuration --- config/prod.exs | 5 ----- config/runtime.exs | 8 ++++++++ documents/prod_files/example_prod_secret.exs | 7 ------- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/config/prod.exs b/config/prod.exs index 414a80b49..8429cccb1 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -63,11 +63,6 @@ config :teiserver, TeiserverWeb.Endpoint, server: true, version: Mix.Project.config()[:version] -config :teiserver, Teiserver.Repo, - pool_size: String.to_integer(System.get_env("POOL_SIZE") || "40"), - timeout: 120_000, - queue_interval: 2000 - # Do not print debug messages in production config :logger, format: "$date $time [$level] $metadata $message\n", diff --git a/config/runtime.exs b/config/runtime.exs index 4acfa8493..9e7cc0831 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -51,6 +51,14 @@ if config_env() == :prod do enable_managed_lobbies: true, tachyon_schema_path: "/apps/teiserver/lib/teiserver-0.1.0/priv/tachyon/schema_v1/*/*/*.json" + config :teiserver, Teiserver.Repo, + username: System.fetch_env!("DB_USERNAME"), + password: System.fetch_env!("DB_PASSWORD"), + database: System.fetch_env!("DB_NAME"), + pool_size: 40, + timeout: 120_000, + queue_interval: 2000 + config :teiserver, TeiserverWeb.Endpoint, url: [host: domain_name], check_origin: ["//#{domain_name}", "//*.#{domain_name}"], diff --git a/documents/prod_files/example_prod_secret.exs b/documents/prod_files/example_prod_secret.exs index b48d1c5a5..2648f9ea3 100644 --- a/documents/prod_files/example_prod_secret.exs +++ b/documents/prod_files/example_prod_secret.exs @@ -6,13 +6,6 @@ import Config secret_key_base = "mix phx.gen.secret" -config :teiserver, Teiserver.Repo, - username: "teiserver_prod", - password: "mix phx.gen.secret", - database: "teiserver_prod", - pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"), - timeout: 30_000 - config :teiserver, Teiserver.Account.Guardian, issuer: "teiserver", secret_key: "mix phx.gen.secret" From 2a1daa00df71eac1bbad2fbc2b168677187cbf84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Sun, 21 Apr 2024 09:06:19 +0100 Subject: [PATCH 07/23] Guardian config to runtime config --- config/prod.exs | 4 ---- config/runtime.exs | 3 +++ documents/prod_files/example_prod_secret.exs | 4 ---- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/config/prod.exs b/config/prod.exs index 8429cccb1..ed8631c7f 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -95,8 +95,4 @@ config :logger, :info_log, metadata: [:request_id, :user_id], level: :info -# Overwritten in secret -config :teiserver, Teiserver.Account.Guardian, - secret_key: "yix2DcXsA9MzAI8WldmYiJ38j2GyyXf5beWGAOJHl0FKNH04n1VACYbepqutma27" - import_config "prod.secret.exs" diff --git a/config/runtime.exs b/config/runtime.exs index 9e7cc0831..35317bc52 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -73,6 +73,9 @@ if config_env() == :prod do http: [:inet6, port: String.to_integer(System.get_env("PORT", "4000"))], secret_key_base: System.fetch_env!("HTTP_SECRET_KEY_BASE") + config :teiserver, Teiserver.Account.Guardian, + issuer: System.fetch_env!("GUARDIAN_ISSUER"), + secret_key: System.fetch_env!("GUARDIAN_SECRET_KEY") end diff --git a/documents/prod_files/example_prod_secret.exs b/documents/prod_files/example_prod_secret.exs index 2648f9ea3..da3c1abeb 100644 --- a/documents/prod_files/example_prod_secret.exs +++ b/documents/prod_files/example_prod_secret.exs @@ -6,10 +6,6 @@ import Config secret_key_base = "mix phx.gen.secret" -config :teiserver, Teiserver.Account.Guardian, - issuer: "teiserver", - secret_key: "mix phx.gen.secret" - config :teiserver, Teiserver.Mailer, noreply_address: "noreply@yourdomain.com", contact_address: "info@yourdomain.com", From 9a00456350243924c2a4df4fa941a6f8b2ef6e6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Sun, 21 Apr 2024 09:07:14 +0100 Subject: [PATCH 08/23] Mailer configuration to runtime config --- config/runtime.exs | 25 +++++++++++++++++++ documents/prod_files/example_prod_secret.exs | 26 -------------------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/config/runtime.exs b/config/runtime.exs index 35317bc52..06edd98cd 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -77,5 +77,30 @@ if config_env() == :prod do issuer: System.fetch_env!("GUARDIAN_ISSUER"), secret_key: System.fetch_env!("GUARDIAN_SECRET_KEY") + config :teiserver, Teiserver.Mailer, + noreply_address: "noreply@#{domain_name}", + contact_address: "info@#{domain_name}", + noreply_name: "Beyond all reason team", + adapter: Bamboo.SMTPAdapter, + server: System.fetch_env!("MAILER_SERVER"), + hostname: domain_name, + # port: 1025, + port: String.to_integer(System.get_env("MAILER_PORT", "587")), + # or {:system, "SMTP_USERNAME"} + username: System.get_env("MAILER_USERNAME", "noreply@#{domain_name}"), + # or {:system, "SMTP_PASSWORD"} + password: System.fetch_env!("MAILER_PASSWORD"), + # tls: :if_available, # can be `:always` or `:never` + # can be `:always` or `:never` + tls: :always, + # or {":system", ALLOWED_TLS_VERSIONS"} w/ comma seprated values (e.g. "tlsv1.1,tlsv1.2") + allowed_tls_versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"], + # can be `true` + ssl: false, + retries: 1, + # can be `true` + no_mx_lookups: false, + # auth: :if_available # can be `always`. If your smtp relay requires authentication set it to `always`. + auth: :always end diff --git a/documents/prod_files/example_prod_secret.exs b/documents/prod_files/example_prod_secret.exs index da3c1abeb..aeb4cf73a 100644 --- a/documents/prod_files/example_prod_secret.exs +++ b/documents/prod_files/example_prod_secret.exs @@ -5,29 +5,3 @@ import Config secret_key_base = "mix phx.gen.secret" - -config :teiserver, Teiserver.Mailer, - noreply_address: "noreply@yourdomain.com", - contact_address: "info@yourdomain.com", - noreply_name: "Name of your game", - adapter: Bamboo.SMTPAdapter, - server: "mailserver", - hostname: "yourdomain.com", - # port: 1025, - port: 587, - # or {:system, "SMTP_USERNAME"} - username: "noreply@yourdomain.com", - # or {:system, "SMTP_PASSWORD"} - password: "mix phx.gen.secret", - # tls: :if_available, # can be `:always` or `:never` - # can be `:always` or `:never` - tls: :always, - # or {":system", ALLOWED_TLS_VERSIONS"} w/ comma seprated values (e.g. "tlsv1.1,tlsv1.2") - allowed_tls_versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"], - # can be `true` - ssl: false, - retries: 1, - # can be `true` - no_mx_lookups: false, - # auth: :if_available # can be `always`. If your smtp relay requires authentication set it to `always`. - auth: :always From 1bfc793421aa7b0134dfd203db80f64056f0950c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Sun, 21 Apr 2024 09:08:31 +0100 Subject: [PATCH 09/23] Logger configuration to runtime config Because having to recompile the application to change some logging config sucks --- config/prod.exs | 32 -------------------------------- config/runtime.exs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/config/prod.exs b/config/prod.exs index ed8631c7f..aa8231100 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -63,36 +63,4 @@ config :teiserver, TeiserverWeb.Endpoint, server: true, version: Mix.Project.config()[:version] -# Do not print debug messages in production -config :logger, - format: "$date $time [$level] $metadata $message\n", - metadata: [:request_id, :user_id], - level: :info - -config :logger, - backends: [ - {LoggerFileBackend, :error_log}, - {LoggerFileBackend, :notice_log}, - {LoggerFileBackend, :info_log}, - :console - ] - -config :logger, :error_log, - path: "/var/log/teiserver/error.log", - format: "$date $time [$level] $metadata $message\n", - metadata: [:request_id, :user_id], - level: :error - -config :logger, :notice_log, - path: "/var/log/teiserver/notice.log", - format: "$date $time [$level] $metadata $message\n", - metadata: [:request_id, :user_id], - level: :notice - -config :logger, :info_log, - path: "/var/log/teiserver/info.log", - format: "$date $time [$level] $metadata $message\n", - metadata: [:request_id, :user_id], - level: :info - import_config "prod.secret.exs" diff --git a/config/runtime.exs b/config/runtime.exs index 06edd98cd..bf8b5807e 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -103,4 +103,37 @@ if config_env() == :prod do # auth: :if_available # can be `always`. If your smtp relay requires authentication set it to `always`. auth: :always + log_root_path = System.fetch_env("LOG_ROOT_PATH", "/var/log/teiserver/") + + config :logger, + backends: [ + {LoggerFileBackend, :error_log}, + {LoggerFileBackend, :notice_log}, + {LoggerFileBackend, :info_log}, + :console + ] + + # Do not print debug messages in production + config :logger, + format: "$date $time [$level] $metadata $message\n", + metadata: [:request_id, :user_id], + level: :info + + config :logger, :error_log, + path: "#{log_root_path}error.log", + format: "$date $time [$level] $metadata $message\n", + metadata: [:request_id, :user_id], + level: :error + + config :logger, :notice_log, + path: "#{log_root_path}notice.log", + format: "$date $time [$level] $metadata $message\n", + metadata: [:request_id, :user_id], + level: :notice + + config :logger, :info_log, + path: "#{log_root_path}info.log", + format: "$date $time [$level] $metadata $message\n", + metadata: [:request_id, :user_id], + level: :info end From 0a705e82366c8a3401c3a96176aec318107ed9b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Sun, 21 Apr 2024 09:11:30 +0100 Subject: [PATCH 10/23] Remove prod_secret file completely --- config/prod.exs | 2 -- documents/guides/deployment.md | 5 +---- documents/prod_files/example_prod_secret.exs | 7 ------- 3 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 documents/prod_files/example_prod_secret.exs diff --git a/config/prod.exs b/config/prod.exs index aa8231100..f3fbc35aa 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -62,5 +62,3 @@ config :teiserver, TeiserverWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json", server: true, version: Mix.Project.config()[:version] - -import_config "prod.secret.exs" diff --git a/documents/guides/deployment.md b/documents/guides/deployment.md index 70a178a2d..abffd693e 100644 --- a/documents/guides/deployment.md +++ b/documents/guides/deployment.md @@ -5,9 +5,6 @@ If you've not already setup your server you might want to check out [documents/g - Locally running Elixir - Docker installed on your computer -### prod.secret.exs -`config/prod.secret.exs` is ignored in the gitignore for obvious reasons. This means you will need to create your own one. Luckily I [made a template for you](/documents/prod_files/example_prod_secret.exs). - #### Dockerfile A docker file is included in the repo but within [documents/prod_files](documents/prod_files) are other docker images providing more control over the building of your image and might be of interest. @@ -38,4 +35,4 @@ docker build --build-arg env=prod \ ``` #!/usr/bin/env bash docker run -v $(pwd):/opt/build --rm -it teiserver:latest /opt/build/bin/build -``` \ No newline at end of file +``` diff --git a/documents/prod_files/example_prod_secret.exs b/documents/prod_files/example_prod_secret.exs deleted file mode 100644 index aeb4cf73a..000000000 --- a/documents/prod_files/example_prod_secret.exs +++ /dev/null @@ -1,7 +0,0 @@ -# In this file, we load production configuration and secrets -# from environment variables. You can also hardcode secrets, -# although such is generally not recommended and you have to -# remember to add this file to your .gitignore. -import Config - -secret_key_base = "mix phx.gen.secret" From 4dbe19ebe9f3cf7b77173ae1ce4bb4c5bec400bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Sun, 21 Apr 2024 09:13:28 +0100 Subject: [PATCH 11/23] Tidy some general config --- config/config.exs | 5 ++++- config/dev.exs | 3 --- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/config.exs b/config/config.exs index b65c7b339..8dbbf3df6 100644 --- a/config/config.exs +++ b/config/config.exs @@ -29,7 +29,10 @@ config :teiserver, TeiserverWeb.Endpoint, formats: [html: TeiserverWeb.ErrorHTML, json: TeiserverWeb.ErrorJSON], layout: false ], - pubsub_server: Teiserver.PubSub + pubsub_server: Teiserver.PubSub, + debug_errors: Config.config_env() == :dev, + code_reloader: Config.config_env() == :dev, + check_origin: Config.config_env() == :prod config :esbuild, version: "0.14.41", diff --git a/config/dev.exs b/config/dev.exs index d18f112fa..5931816ed 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -20,9 +20,6 @@ config :teiserver, Teiserver.Repo, # with webpack to recompile .js and .css sources. config :teiserver, TeiserverWeb.Endpoint, http: [ip: {127, 0, 0, 1}, port: 4000], - debug_errors: true, - code_reloader: true, - check_origin: false, watchers: [ # Start the esbuild watcher by calling Esbuild.install_and_run(:default, args) esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]}, From 3851789c8af1a6c84083b497ad35e18b46993457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Sun, 21 Apr 2024 09:19:50 +0100 Subject: [PATCH 12/23] Add config helpers for simple parsing --- config/runtime.exs | 49 ++++++++++++++++----------------- lib/teiserver/config_helpers.ex | 36 ++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 25 deletions(-) create mode 100644 lib/teiserver/config_helpers.ex diff --git a/config/runtime.exs b/config/runtime.exs index bf8b5807e..022c32e41 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -16,7 +16,7 @@ import Config # # Alternatively, you can use `mix phx.gen.release` to generate a `bin/server` # script that automatically sets the env var above. -if System.get_env("PHX_SERVER") do +if Teiserver.ConfigHelpers.get_env("PHX_SERVER", nil) do config :teiserver, TeiserverWeb.Endpoint, server: true end @@ -25,12 +25,12 @@ end # are just fine if config_env() == :prod do # used for mailing, checking origins, finding tls certs… - domain_name = System.get_env("DOMAIN_NAME", "beyondallreason.info") + domain_name = Teiserver.ConfigHelpers.get_env("DOMAIN_NAME", "beyondallreason.info") certificates = [ - keyfile: System.fetch_env!("TLS_PRIVATE_KEY_PATH"), - certfile: System.fetch_env!("TLS_CERT_PATH"), - cacertfile: System.fetch_env!("TLS_CA_CERT_PATH") + keyfile: Teiserver.ConfigHelpers.get_env("TLS_PRIVATE_KEY_PATH"), + certfile: Teiserver.ConfigHelpers.get_env("TLS_CERT_PATH"), + cacertfile: Teiserver.ConfigHelpers.get_env("TLS_CA_CERT_PATH") ] # this is used in lib/teiserver_web/controllers/account/setup_controller.ex @@ -44,17 +44,17 @@ if config_env() == :prod do game_name_short: "BAR", main_website: "https://www.beyondallreason.info/", privacy_email: "privacy@beyondallreason.info", - discord: System.get_env("DISCORD_LINK"), + discord: Teiserver.ConfigHelpers.get_env("DISCORD_LINK", nil), certs: certificates, enable_benchmark: false, - node_name: System.fetch_env!("NODE_NAME"), + node_name: Teiserver.ConfigHelpers.get_env("NODE_NAME"), enable_managed_lobbies: true, tachyon_schema_path: "/apps/teiserver/lib/teiserver-0.1.0/priv/tachyon/schema_v1/*/*/*.json" config :teiserver, Teiserver.Repo, - username: System.fetch_env!("DB_USERNAME"), - password: System.fetch_env!("DB_PASSWORD"), - database: System.fetch_env!("DB_NAME"), + username: Teiserver.ConfigHelpers.get_env("DB_USERNAME"), + password: Teiserver.ConfigHelpers.get_env("DB_PASSWORD"), + database: Teiserver.ConfigHelpers.get_env("DB_NAME"), pool_size: 40, timeout: 120_000, queue_interval: 2000 @@ -68,42 +68,41 @@ if config_env() == :prod do versions: [:"tlsv1.2"], # dhfile is not supported for tls 1.3 # https://www.erlang.org/doc/man/ssl.html#type-dh_file - dhfile: System.fetch_env!("TLS_DH_FILE_PATH") + dhfile: Teiserver.ConfigHelpers.get_env("TLS_DH_FILE_PATH") ], - http: [:inet6, port: String.to_integer(System.get_env("PORT", "4000"))], - secret_key_base: System.fetch_env!("HTTP_SECRET_KEY_BASE") + http: [:inet6, port: Teiserver.ConfigHelpers.get_env("PORT", "4000", :int)], + secret_key_base: Teiserver.ConfigHelpers.get_env("HTTP_SECRET_KEY_BASE") config :teiserver, Teiserver.Account.Guardian, - issuer: System.fetch_env!("GUARDIAN_ISSUER"), - secret_key: System.fetch_env!("GUARDIAN_SECRET_KEY") + issuer: Teiserver.ConfigHelpers.get_env("GUARDIAN_ISSUER", "teiserver"), + secret_key: Teiserver.ConfigHelpers.get_env("GUARDIAN_SECRET_KEY") config :teiserver, Teiserver.Mailer, noreply_address: "noreply@#{domain_name}", - contact_address: "info@#{domain_name}", - noreply_name: "Beyond all reason team", + noreply_address: + Teiserver.ConfigHelpers.get_env("TEI_NOREPLY_EMAIL_ADDRESS", "noreply@#{domain_name}"), + contact_address: + Teiserver.ConfigHelpers.get_env("TEI_CONTACT_EMAIL_ADDRESS", "info@#{domain_name}"), adapter: Bamboo.SMTPAdapter, - server: System.fetch_env!("MAILER_SERVER"), + server: Teiserver.ConfigHelpers.get_env("MAILER_SERVER"), hostname: domain_name, # port: 1025, - port: String.to_integer(System.get_env("MAILER_PORT", "587")), + port: Teiserver.ConfigHelpers.get_env("MAILER_PORT", "587", :bool), # or {:system, "SMTP_USERNAME"} - username: System.get_env("MAILER_USERNAME", "noreply@#{domain_name}"), + username: Teiserver.ConfigHelpers.get_env("MAILER_USERNAME", "noreply@#{domain_name}"), # or {:system, "SMTP_PASSWORD"} - password: System.fetch_env!("MAILER_PASSWORD"), + password: Teiserver.ConfigHelpers.get_env("MAILER_PASSWORD"), # tls: :if_available, # can be `:always` or `:never` # can be `:always` or `:never` tls: :always, # or {":system", ALLOWED_TLS_VERSIONS"} w/ comma seprated values (e.g. "tlsv1.1,tlsv1.2") allowed_tls_versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"], # can be `true` - ssl: false, - retries: 1, - # can be `true` no_mx_lookups: false, # auth: :if_available # can be `always`. If your smtp relay requires authentication set it to `always`. auth: :always - log_root_path = System.fetch_env("LOG_ROOT_PATH", "/var/log/teiserver/") + log_root_path = Teiserver.ConfigHelpers.get_env("LOG_ROOT_PATH", "/var/log/teiserver/") config :logger, backends: [ diff --git a/lib/teiserver/config_helpers.ex b/lib/teiserver/config_helpers.ex new file mode 100644 index 000000000..b399aad68 --- /dev/null +++ b/lib/teiserver/config_helpers.ex @@ -0,0 +1,36 @@ +# Taken from https://gitlab.com/code-stats/code-stats/-/blob/b1cf53462a3fa34369eaa06494754c7ae38aed2a/lib/code_stats/config_helpers.ex +defmodule Teiserver.ConfigHelpers do + @type config_type :: :str | :int | :bool | :json + + @doc """ + Get value from environment variable, converting it to the given type if needed. + + If no default value is given, or `:no_default` is given as the default, an error is raised if the variable is not + set. + """ + @spec get_env(String.t(), :no_default | any(), config_type()) :: any() + def get_env(var, default \\ :no_default, type \\ :str) + + def get_env(var, :no_default, type) do + System.fetch_env!(var) + |> get_with_type(type) + end + + def get_env(var, default, type) do + with {:ok, val} <- System.fetch_env(var) do + get_with_type(val, type) + else + :error -> default + end + end + + @spec get_with_type(String.t(), config_type()) :: any() + defp get_with_type(val, type) + + defp get_with_type(val, :str), do: val + defp get_with_type(val, :int), do: String.to_integer(val) + defp get_with_type("true", :bool), do: true + defp get_with_type("false", :bool), do: false + defp get_with_type(val, :json), do: Jason.decode!(val) + defp get_with_type(val, type), do: raise("Cannot convert to #{inspect(type)}: #{inspect(val)}") +end From aaaff243ac918c524d914abdebe826d2bad1a6de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Sun, 21 Apr 2024 09:43:05 +0100 Subject: [PATCH 13/23] Add an example of environment file for sensitive values --- config/runtime.exs | 4 ++ documents/prod_files/example-environment-file | 41 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 documents/prod_files/example-environment-file diff --git a/config/runtime.exs b/config/runtime.exs index 022c32e41..e532df076 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -7,6 +7,10 @@ import Config # any compile-time configuration in here, as it won't be applied. # The block below contains prod specific runtime configuration. +# ## Sensitive values should be passed through the environment. An example +# EnvironmentFile that can be used with systemd is under +# documents/prod_files/example-environment-file + # ## Using releases # # If you use `mix release`, you need to explicitly enable the server diff --git a/documents/prod_files/example-environment-file b/documents/prod_files/example-environment-file new file mode 100644 index 000000000..445013e15 --- /dev/null +++ b/documents/prod_files/example-environment-file @@ -0,0 +1,41 @@ +# This file is an example of a systemd environment file to configure a running service +# In the systemd unit file, it should be setup with a line: +# EnvironmentFile=/etc/sysconfig/teiserver +# Be careful, if this line is in the systemd unit definition but the file doesn't exist +# the service will be silently disabled + +# For more info, see: +# https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#EnvironmentFile= +# and also: +# https://fedoraproject.org/wiki/Packaging:Systemd#EnvironmentFiles_and_support_for_/etc/sysconfig_files + +# To easily load all these in your shell's environment: +# ``` +# set -o allexport; source documents/prod_files/example-environment-file; set +o allexport +# ``` + +# General secrets +PHX_SERVER=true +DISCORD_LINK=https://discord.com/whatever-link +NODE_NAME=staging-node-1 + +# DB configuration +DB_USERNAME=teiserver-prod +DB_PASSWORD=verysecret-password +DB_NAME=teiserver_prod + +# TLS config +HTTPS_DH_FILE_PATH=/var/www/tls/dh-params.pem + +# For cookie encryption +HTTP_SECRET_KEY_BASE=another-very-long-secret + +# For Guardian (authentication) +GUARDIAN_SECRET_KEY=yet-another-random-key-to-keep-secret + +# Email +MAILER_SERVER=mailserver +MAILER_USERNAME=noreply@beyondallreason.info +MAILER_PASSWORD=correct-battery-staple-horse-xkcd-936 + +# vim: ft=systemd From c547c2b44bdd3971e7d44504fb20ecfb45d2bb43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Mon, 22 Apr 2024 20:39:35 +0100 Subject: [PATCH 14/23] Endpoint config to match prod --- config/runtime.exs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/config/runtime.exs b/config/runtime.exs index e532df076..445ef7e14 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -63,16 +63,23 @@ if config_env() == :prod do timeout: 120_000, queue_interval: 2000 + check_origin = + if Teiserver.ConfigHelpers.get_env("SHOULD_CHECK_ORIGIN", false, :bool) do + ["//#{domain_name}", "//*.#{domain_name}"] + else + false + end + config :teiserver, TeiserverWeb.Endpoint, url: [host: domain_name], - check_origin: ["//#{domain_name}", "//*.#{domain_name}"], + check_origin: check_origin, https: certificates ++ [ versions: [:"tlsv1.2"], # dhfile is not supported for tls 1.3 # https://www.erlang.org/doc/man/ssl.html#type-dh_file - dhfile: Teiserver.ConfigHelpers.get_env("TLS_DH_FILE_PATH") + dhfile: Teiserver.ConfigHelpers.get_env("TLS_DH_FILE_PATH", "/etc/ssl/dhparam.pem") ], http: [:inet6, port: Teiserver.ConfigHelpers.get_env("PORT", "4000", :int)], secret_key_base: Teiserver.ConfigHelpers.get_env("HTTP_SECRET_KEY_BASE") From e74eaead691df532702d6970d7930341cbbe1bed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Mon, 22 Apr 2024 20:43:51 +0100 Subject: [PATCH 15/23] General config to match prod --- config/runtime.exs | 12 +++++++++--- documents/prod_files/example-environment-file | 1 - 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/config/runtime.exs b/config/runtime.exs index 445ef7e14..3dff1f4d2 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -44,16 +44,22 @@ if config_env() == :prod do config :teiserver, Teiserver.Setup, key: nil config :teiserver, Teiserver, - game_name: "Beyond all reason", + game_name: "Beyond All Reason", game_name_short: "BAR", main_website: "https://www.beyondallreason.info/", privacy_email: "privacy@beyondallreason.info", - discord: Teiserver.ConfigHelpers.get_env("DISCORD_LINK", nil), + discord: "https://discord.gg/beyond-all-reason", certs: certificates, + website: [ + url: "beyondallreason.info" + ], + server_flag: "GB-WLS", enable_benchmark: false, node_name: Teiserver.ConfigHelpers.get_env("NODE_NAME"), + extra_logging: false, enable_managed_lobbies: true, - tachyon_schema_path: "/apps/teiserver/lib/teiserver-0.1.0/priv/tachyon/schema_v1/*/*/*.json" + user_agreement: + "A verification code has been sent to your email address. Please read our terms of service at https://#{domain_name}/privacy_policy and the code of conduct at https://www.beyondallreason.info/code-of-conduct. Then enter your six digit code below if you agree to the terms." config :teiserver, Teiserver.Repo, username: Teiserver.ConfigHelpers.get_env("DB_USERNAME"), diff --git a/documents/prod_files/example-environment-file b/documents/prod_files/example-environment-file index 445013e15..36b4b2036 100644 --- a/documents/prod_files/example-environment-file +++ b/documents/prod_files/example-environment-file @@ -16,7 +16,6 @@ # General secrets PHX_SERVER=true -DISCORD_LINK=https://discord.com/whatever-link NODE_NAME=staging-node-1 # DB configuration From 1cc98fa5f64f897f8c75517702c916c362ad480a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Mon, 22 Apr 2024 20:52:19 +0100 Subject: [PATCH 16/23] Mailer configuration to match prod --- config/runtime.exs | 30 +++++++++++-------- documents/prod_files/example-environment-file | 6 ++-- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/config/runtime.exs b/config/runtime.exs index 3dff1f4d2..ce40125e2 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -94,26 +94,30 @@ if config_env() == :prod do issuer: Teiserver.ConfigHelpers.get_env("GUARDIAN_ISSUER", "teiserver"), secret_key: Teiserver.ConfigHelpers.get_env("GUARDIAN_SECRET_KEY") + config :teiserver, Teiserver.Mailer, - noreply_address: "noreply@#{domain_name}", - noreply_address: - Teiserver.ConfigHelpers.get_env("TEI_NOREPLY_EMAIL_ADDRESS", "noreply@#{domain_name}"), - contact_address: - Teiserver.ConfigHelpers.get_env("TEI_CONTACT_EMAIL_ADDRESS", "info@#{domain_name}"), adapter: Bamboo.SMTPAdapter, - server: Teiserver.ConfigHelpers.get_env("MAILER_SERVER"), - hostname: domain_name, + contact_address: + Teiserver.ConfigHelpers.get_env("CONTACT_EMAIL_ADDRESS", "info@#{domain_name}"), + noreply_name: "Beyond All Reason", + noreply_address: + Teiserver.ConfigHelpers.get_env("NOREPLY_EMAIL_ADDRESS", "noreply@#{domain_name}"), + smtp_server: Teiserver.ConfigHelpers.get_env("SMTP_SERVER"), + hostname: Teiserver.ConfigHelpers.get_env("SMTP_HOSTNAME"), # port: 1025, - port: Teiserver.ConfigHelpers.get_env("MAILER_PORT", "587", :bool), - # or {:system, "SMTP_USERNAME"} - username: Teiserver.ConfigHelpers.get_env("MAILER_USERNAME", "noreply@#{domain_name}"), - # or {:system, "SMTP_PASSWORD"} - password: Teiserver.ConfigHelpers.get_env("MAILER_PASSWORD"), + port: Teiserver.ConfigHelpers.get_env("SMTP_PORT", "587", :int), + username: Teiserver.ConfigHelpers.get_env("SMTP_USERNAME"), + password: Teiserver.ConfigHelpers.get_env("SMTP_PASSWORD"), # tls: :if_available, # can be `:always` or `:never` # can be `:always` or `:never` tls: :always, + tls_verify: + if(Teiserver.ConfigHelpers.get_env("SMTP_TLS_VERIFY", true, :bool), + do: :verify_peer, + else: :verify_none + ), # or {":system", ALLOWED_TLS_VERSIONS"} w/ comma seprated values (e.g. "tlsv1.1,tlsv1.2") - allowed_tls_versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"], + allowed_tls_versions: [:"tlsv1.2"], # can be `true` no_mx_lookups: false, # auth: :if_available # can be `always`. If your smtp relay requires authentication set it to `always`. diff --git a/documents/prod_files/example-environment-file b/documents/prod_files/example-environment-file index 36b4b2036..06281d574 100644 --- a/documents/prod_files/example-environment-file +++ b/documents/prod_files/example-environment-file @@ -33,8 +33,8 @@ HTTP_SECRET_KEY_BASE=another-very-long-secret GUARDIAN_SECRET_KEY=yet-another-random-key-to-keep-secret # Email -MAILER_SERVER=mailserver -MAILER_USERNAME=noreply@beyondallreason.info -MAILER_PASSWORD=correct-battery-staple-horse-xkcd-936 +SMTP_SERVER=mailserver +SMTP_USERNAME=noreply@beyondallreason.info +SMTP_PASSWORD=correct-battery-staple-horse-xkcd-936 # vim: ft=systemd From 0362cf0d47200ca98be1d3b0527b3f4bb2a09c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Mon, 22 Apr 2024 20:54:44 +0100 Subject: [PATCH 17/23] Allow email to be deactivated at startup --- config/runtime.exs | 59 ++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/config/runtime.exs b/config/runtime.exs index ce40125e2..0e51d0d17 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -94,34 +94,37 @@ if config_env() == :prod do issuer: Teiserver.ConfigHelpers.get_env("GUARDIAN_ISSUER", "teiserver"), secret_key: Teiserver.ConfigHelpers.get_env("GUARDIAN_SECRET_KEY") - - config :teiserver, Teiserver.Mailer, - adapter: Bamboo.SMTPAdapter, - contact_address: - Teiserver.ConfigHelpers.get_env("CONTACT_EMAIL_ADDRESS", "info@#{domain_name}"), - noreply_name: "Beyond All Reason", - noreply_address: - Teiserver.ConfigHelpers.get_env("NOREPLY_EMAIL_ADDRESS", "noreply@#{domain_name}"), - smtp_server: Teiserver.ConfigHelpers.get_env("SMTP_SERVER"), - hostname: Teiserver.ConfigHelpers.get_env("SMTP_HOSTNAME"), - # port: 1025, - port: Teiserver.ConfigHelpers.get_env("SMTP_PORT", "587", :int), - username: Teiserver.ConfigHelpers.get_env("SMTP_USERNAME"), - password: Teiserver.ConfigHelpers.get_env("SMTP_PASSWORD"), - # tls: :if_available, # can be `:always` or `:never` - # can be `:always` or `:never` - tls: :always, - tls_verify: - if(Teiserver.ConfigHelpers.get_env("SMTP_TLS_VERIFY", true, :bool), - do: :verify_peer, - else: :verify_none - ), - # or {":system", ALLOWED_TLS_VERSIONS"} w/ comma seprated values (e.g. "tlsv1.1,tlsv1.2") - allowed_tls_versions: [:"tlsv1.2"], - # can be `true` - no_mx_lookups: false, - # auth: :if_available # can be `always`. If your smtp relay requires authentication set it to `always`. - auth: :always + if Teiserver.ConfigHelpers.get_env("ENABLE_EMAIL_INTEGRATION", :bool) do + smtp_server = Teiserver.ConfigHelpers.get_env("SMTP_HOSTNAME") + + config :teiserver, Teiserver.Mailer, + adapter: Bamboo.SMTPAdapter, + contact_address: + Teiserver.ConfigHelpers.get_env("CONTACT_EMAIL_ADDRESS", "info@#{domain_name}"), + noreply_name: "Beyond All Reason", + noreply_address: + Teiserver.ConfigHelpers.get_env("NOREPLY_EMAIL_ADDRESS", "noreply@#{domain_name}"), + smtp_server: Teiserver.ConfigHelpers.get_env("SMTP_SERVER"), + hostname: Teiserver.ConfigHelpers.get_env("SMTP_HOSTNAME"), + # port: 1025, + port: Teiserver.ConfigHelpers.get_env("SMTP_PORT", "587", :int), + username: Teiserver.ConfigHelpers.get_env("SMTP_USERNAME"), + password: Teiserver.ConfigHelpers.get_env("SMTP_PASSWORD"), + # tls: :if_available, # can be `:always` or `:never` + # can be `:always` or `:never` + tls: :always, + tls_verify: + if(Teiserver.ConfigHelpers.get_env("SMTP_TLS_VERIFY", true, :bool), + do: :verify_peer, + else: :verify_none + ), + # or {":system", ALLOWED_TLS_VERSIONS"} w/ comma seprated values (e.g. "tlsv1.1,tlsv1.2") + allowed_tls_versions: [:"tlsv1.2"], + # can be `true` + no_mx_lookups: false, + # auth: :if_available # can be `always`. If your smtp relay requires authentication set it to `always`. + auth: :always + end log_root_path = Teiserver.ConfigHelpers.get_env("LOG_ROOT_PATH", "/var/log/teiserver/") From c57f173db059790bb1dd7e86923218197e4afedb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Sun, 28 Apr 2024 16:27:19 +0100 Subject: [PATCH 18/23] Allow ports config to be set at runtime through env --- config/runtime.exs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config/runtime.exs b/config/runtime.exs index 0e51d0d17..5bbc6b57b 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -49,6 +49,13 @@ if config_env() == :prod do main_website: "https://www.beyondallreason.info/", privacy_email: "privacy@beyondallreason.info", discord: "https://discord.gg/beyond-all-reason", + ports: [ + tcp: Teiserver.ConfigHelpers.get_env("SPRING_TCP_PORT", 8200, :int), + tls: Teiserver.ConfigHelpers.get_env("SPRING_TLS_PORT", 8201, :int), + # this can likely be deprecated and removed. It's for an old version + # of tachyon running on another TLS socket + tachyon: Teiserver.ConfigHelpers.get_env("TACHYON_TLS_PORT", 8202, :int) + ], certs: certificates, website: [ url: "beyondallreason.info" From 3d79f34fab62e8494f22d15f471301a5dae586bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Wed, 8 May 2024 20:17:53 +0100 Subject: [PATCH 19/23] Prefix all env var with TEI leaves PHX_SERVER alone though, since it's something coming with phoenix, better leave that as a default so the rest of the tooling like bundling and generating start script can work without modification. --- config/runtime.exs | 56 +++++++++---------- documents/prod_files/example-environment-file | 20 +++---- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/config/runtime.exs b/config/runtime.exs index 5bbc6b57b..fb6d7c617 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -29,12 +29,12 @@ end # are just fine if config_env() == :prod do # used for mailing, checking origins, finding tls certs… - domain_name = Teiserver.ConfigHelpers.get_env("DOMAIN_NAME", "beyondallreason.info") + domain_name = Teiserver.ConfigHelpers.get_env("TEI_DOMAIN_NAME", "beyondallreason.info") certificates = [ - keyfile: Teiserver.ConfigHelpers.get_env("TLS_PRIVATE_KEY_PATH"), - certfile: Teiserver.ConfigHelpers.get_env("TLS_CERT_PATH"), - cacertfile: Teiserver.ConfigHelpers.get_env("TLS_CA_CERT_PATH") + keyfile: Teiserver.ConfigHelpers.get_env("TEI_TLS_PRIVATE_KEY_PATH"), + certfile: Teiserver.ConfigHelpers.get_env("TEI_TLS_CERT_PATH"), + cacertfile: Teiserver.ConfigHelpers.get_env("TEI_TLS_CA_CERT_PATH") ] # this is used in lib/teiserver_web/controllers/account/setup_controller.ex @@ -50,11 +50,11 @@ if config_env() == :prod do privacy_email: "privacy@beyondallreason.info", discord: "https://discord.gg/beyond-all-reason", ports: [ - tcp: Teiserver.ConfigHelpers.get_env("SPRING_TCP_PORT", 8200, :int), - tls: Teiserver.ConfigHelpers.get_env("SPRING_TLS_PORT", 8201, :int), + tcp: Teiserver.ConfigHelpers.get_env("TEI_SPRING_TCP_PORT", 8200, :int), + tls: Teiserver.ConfigHelpers.get_env("TEI_SPRING_TLS_PORT", 8201, :int), # this can likely be deprecated and removed. It's for an old version # of tachyon running on another TLS socket - tachyon: Teiserver.ConfigHelpers.get_env("TACHYON_TLS_PORT", 8202, :int) + tachyon: Teiserver.ConfigHelpers.get_env("TEI_TACHYON_TLS_PORT", 8202, :int) ], certs: certificates, website: [ @@ -62,22 +62,22 @@ if config_env() == :prod do ], server_flag: "GB-WLS", enable_benchmark: false, - node_name: Teiserver.ConfigHelpers.get_env("NODE_NAME"), + node_name: Teiserver.ConfigHelpers.get_env("TEI_NODE_NAME"), extra_logging: false, enable_managed_lobbies: true, user_agreement: "A verification code has been sent to your email address. Please read our terms of service at https://#{domain_name}/privacy_policy and the code of conduct at https://www.beyondallreason.info/code-of-conduct. Then enter your six digit code below if you agree to the terms." config :teiserver, Teiserver.Repo, - username: Teiserver.ConfigHelpers.get_env("DB_USERNAME"), - password: Teiserver.ConfigHelpers.get_env("DB_PASSWORD"), - database: Teiserver.ConfigHelpers.get_env("DB_NAME"), + username: Teiserver.ConfigHelpers.get_env("TEI_DB_USERNAME"), + password: Teiserver.ConfigHelpers.get_env("TEI_DB_PASSWORD"), + database: Teiserver.ConfigHelpers.get_env("TEI_DB_NAME"), pool_size: 40, timeout: 120_000, queue_interval: 2000 check_origin = - if Teiserver.ConfigHelpers.get_env("SHOULD_CHECK_ORIGIN", false, :bool) do + if Teiserver.ConfigHelpers.get_env("TEI_SHOULD_CHECK_ORIGIN", false, :bool) do ["//#{domain_name}", "//*.#{domain_name}"] else false @@ -92,36 +92,34 @@ if config_env() == :prod do versions: [:"tlsv1.2"], # dhfile is not supported for tls 1.3 # https://www.erlang.org/doc/man/ssl.html#type-dh_file - dhfile: Teiserver.ConfigHelpers.get_env("TLS_DH_FILE_PATH", "/etc/ssl/dhparam.pem") + dhfile: Teiserver.ConfigHelpers.get_env("TEI_TLS_DH_FILE_PATH", "/etc/ssl/dhparam.pem") ], - http: [:inet6, port: Teiserver.ConfigHelpers.get_env("PORT", "4000", :int)], - secret_key_base: Teiserver.ConfigHelpers.get_env("HTTP_SECRET_KEY_BASE") + http: [:inet6, port: Teiserver.ConfigHelpers.get_env("TEI_PORT", "4000", :int)], + secret_key_base: Teiserver.ConfigHelpers.get_env("TEI_HTTP_SECRET_KEY_BASE") config :teiserver, Teiserver.Account.Guardian, - issuer: Teiserver.ConfigHelpers.get_env("GUARDIAN_ISSUER", "teiserver"), - secret_key: Teiserver.ConfigHelpers.get_env("GUARDIAN_SECRET_KEY") - - if Teiserver.ConfigHelpers.get_env("ENABLE_EMAIL_INTEGRATION", :bool) do - smtp_server = Teiserver.ConfigHelpers.get_env("SMTP_HOSTNAME") + issuer: Teiserver.ConfigHelpers.get_env("TEI_GUARDIAN_ISSUER", "teiserver"), + secret_key: Teiserver.ConfigHelpers.get_env("TEI_GUARDIAN_SECRET_KEY") + if Teiserver.ConfigHelpers.get_env("TEI_ENABLE_EMAIL_INTEGRATION", :bool) do config :teiserver, Teiserver.Mailer, adapter: Bamboo.SMTPAdapter, contact_address: - Teiserver.ConfigHelpers.get_env("CONTACT_EMAIL_ADDRESS", "info@#{domain_name}"), + Teiserver.ConfigHelpers.get_env("TEI_CONTACT_EMAIL_ADDRESS", "info@#{domain_name}"), noreply_name: "Beyond All Reason", noreply_address: - Teiserver.ConfigHelpers.get_env("NOREPLY_EMAIL_ADDRESS", "noreply@#{domain_name}"), - smtp_server: Teiserver.ConfigHelpers.get_env("SMTP_SERVER"), - hostname: Teiserver.ConfigHelpers.get_env("SMTP_HOSTNAME"), + Teiserver.ConfigHelpers.get_env("TEI_NOREPLY_EMAIL_ADDRESS", "noreply@#{domain_name}"), + smtp_server: Teiserver.ConfigHelpers.get_env("TEI_SMTP_SERVER"), + hostname: Teiserver.ConfigHelpers.get_env("TEI_SMTP_HOSTNAME"), # port: 1025, - port: Teiserver.ConfigHelpers.get_env("SMTP_PORT", "587", :int), - username: Teiserver.ConfigHelpers.get_env("SMTP_USERNAME"), - password: Teiserver.ConfigHelpers.get_env("SMTP_PASSWORD"), + port: Teiserver.ConfigHelpers.get_env("TEI_SMTP_PORT", "587", :int), + username: Teiserver.ConfigHelpers.get_env("TEI_SMTP_USERNAME"), + password: Teiserver.ConfigHelpers.get_env("TEI_SMTP_PASSWORD"), # tls: :if_available, # can be `:always` or `:never` # can be `:always` or `:never` tls: :always, tls_verify: - if(Teiserver.ConfigHelpers.get_env("SMTP_TLS_VERIFY", true, :bool), + if(Teiserver.ConfigHelpers.get_env("TEI_SMTP_TLS_VERIFY", true, :bool), do: :verify_peer, else: :verify_none ), @@ -133,7 +131,7 @@ if config_env() == :prod do auth: :always end - log_root_path = Teiserver.ConfigHelpers.get_env("LOG_ROOT_PATH", "/var/log/teiserver/") + log_root_path = Teiserver.ConfigHelpers.get_env("TEI_LOG_ROOT_PATH", "/var/log/teiserver/") config :logger, backends: [ diff --git a/documents/prod_files/example-environment-file b/documents/prod_files/example-environment-file index 06281d574..fa3c6be47 100644 --- a/documents/prod_files/example-environment-file +++ b/documents/prod_files/example-environment-file @@ -16,25 +16,25 @@ # General secrets PHX_SERVER=true -NODE_NAME=staging-node-1 +TEI_NODE_NAME=staging-node-1 # DB configuration -DB_USERNAME=teiserver-prod -DB_PASSWORD=verysecret-password -DB_NAME=teiserver_prod +TEI_DB_USERNAME=teiserver-prod +TEI_DB_PASSWORD=verysecret-password +TEI_DB_NAME=teiserver_prod # TLS config -HTTPS_DH_FILE_PATH=/var/www/tls/dh-params.pem +TEI_HTTPS_DH_FILE_PATH=/var/www/tls/dh-params.pem # For cookie encryption -HTTP_SECRET_KEY_BASE=another-very-long-secret +TEI_HTTP_SECRET_KEY_BASE=another-very-long-secret # For Guardian (authentication) -GUARDIAN_SECRET_KEY=yet-another-random-key-to-keep-secret +TEI_GUARDIAN_SECRET_KEY=yet-another-random-key-to-keep-secret # Email -SMTP_SERVER=mailserver -SMTP_USERNAME=noreply@beyondallreason.info -SMTP_PASSWORD=correct-battery-staple-horse-xkcd-936 +TEI_SMTP_SERVER=mailserver +TEI_SMTP_USERNAME=noreply@beyondallreason.info +TEI_SMTP_PASSWORD=correct-battery-staple-horse-xkcd-936 # vim: ft=systemd From 6ec903a8de5476ba8755f768141dc5214a1bed93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Sat, 11 May 2024 07:56:50 +0100 Subject: [PATCH 20/23] Make example file usable locally --- documents/prod_files/example-environment-file | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/documents/prod_files/example-environment-file b/documents/prod_files/example-environment-file index fa3c6be47..e9e586b36 100644 --- a/documents/prod_files/example-environment-file +++ b/documents/prod_files/example-environment-file @@ -19,22 +19,33 @@ PHX_SERVER=true TEI_NODE_NAME=staging-node-1 # DB configuration -TEI_DB_USERNAME=teiserver-prod -TEI_DB_PASSWORD=verysecret-password -TEI_DB_NAME=teiserver_prod +TEI_DB_HOSTNAME=localhost +TEI_DB_USERNAME=teiserver_dev +TEI_DB_PASSWORD=123456789 +TEI_DB_NAME=teiserver_dev # TLS config -TEI_HTTPS_DH_FILE_PATH=/var/www/tls/dh-params.pem +TEI_TLS_PRIVATE_KEY_PATH=priv/certs/localhost.key +TEI_TLS_CERT_PATH=priv/certs/localhost.crt +TEI_TLS_CA_CERT_PATH=priv/certs/localhost.crt +TEI_TLS_DH_FILE_PATH=priv/certs/dh-params.pem -# For cookie encryption -TEI_HTTP_SECRET_KEY_BASE=another-very-long-secret +# For cookie encryption, must be at least 64 bytes +TEI_HTTP_SECRET_KEY_BASE=2f894df108701d787156761fe6c122050a8f0f78426de0ea62593e766b9ffcf0f321ce66aef5e8948bb89dc9cc2f687797e2c30100eb001ff87bab23a005091e # For Guardian (authentication) TEI_GUARDIAN_SECRET_KEY=yet-another-random-key-to-keep-secret # Email -TEI_SMTP_SERVER=mailserver +TEI_ENABLE_EMAIL_INTEGRATION=true +# this assume you're running the container smtp4dev as explained in: +# https://github.com/beyond-all-reason/ansible-teiserver?tab=readme-ov-file#email +TEI_SMTP_SERVER=127.0.0.1 +TEI_SMTP_PORT=2525 +# the domain of the email +TEI_SMTP_HOSTNAME=beyondallreason.info TEI_SMTP_USERNAME=noreply@beyondallreason.info TEI_SMTP_PASSWORD=correct-battery-staple-horse-xkcd-936 +TEI_SMTP_TLS_VERIFY=false # vim: ft=systemd From 5cd1cd7d60c872da209bbf4286b8bdef79de5acd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Sat, 11 May 2024 07:59:42 +0100 Subject: [PATCH 21/23] add hostname for DB in env var --- config/runtime.exs | 1 + 1 file changed, 1 insertion(+) diff --git a/config/runtime.exs b/config/runtime.exs index fb6d7c617..9178bb81b 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -69,6 +69,7 @@ if config_env() == :prod do "A verification code has been sent to your email address. Please read our terms of service at https://#{domain_name}/privacy_policy and the code of conduct at https://www.beyondallreason.info/code-of-conduct. Then enter your six digit code below if you agree to the terms." config :teiserver, Teiserver.Repo, + hostname: Teiserver.ConfigHelpers.get_env("TEI_DB_HOSTNAME"), username: Teiserver.ConfigHelpers.get_env("TEI_DB_USERNAME"), password: Teiserver.ConfigHelpers.get_env("TEI_DB_PASSWORD"), database: Teiserver.ConfigHelpers.get_env("TEI_DB_NAME"), From 5cf40033b1d09710c865fc43c834bd99f6a9140b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Sun, 12 May 2024 07:07:24 +0100 Subject: [PATCH 22/23] Key to setup root user from environment Set to nil by default, if the root user is already setup, the env var should be disabled. --- config/runtime.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/runtime.exs b/config/runtime.exs index 9178bb81b..bc83914e1 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -40,8 +40,8 @@ if config_env() == :prod do # this is used in lib/teiserver_web/controllers/account/setup_controller.ex # as a special endpoint to create the root user. Setting it to empty or nil # will disable the functionality completely. - # There is already a root user, so disable it - config :teiserver, Teiserver.Setup, key: nil + config :teiserver, Teiserver.Setup, + key: Teiserver.ConfigHelpers.get_env("TEI_SETUP_ROOT_KEY", nil) config :teiserver, Teiserver, game_name: "Beyond All Reason", From 2bff16d1f498a57c74db79a43af0ece1c23925f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Tue, 14 May 2024 20:10:28 +0100 Subject: [PATCH 23/23] Fix mailer config --- config/runtime.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/runtime.exs b/config/runtime.exs index bc83914e1..58ed7be40 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -110,7 +110,7 @@ if config_env() == :prod do noreply_name: "Beyond All Reason", noreply_address: Teiserver.ConfigHelpers.get_env("TEI_NOREPLY_EMAIL_ADDRESS", "noreply@#{domain_name}"), - smtp_server: Teiserver.ConfigHelpers.get_env("TEI_SMTP_SERVER"), + server: Teiserver.ConfigHelpers.get_env("TEI_SMTP_SERVER"), hostname: Teiserver.ConfigHelpers.get_env("TEI_SMTP_HOSTNAME"), # port: 1025, port: Teiserver.ConfigHelpers.get_env("TEI_SMTP_PORT", "587", :int),