analytics/config/runtime.exs
2021-11-05 14:58:57 +02:00

432 lines
13 KiB
Elixir
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Config
import Plausible.ConfigHelpers
if config_env() in [:dev, :test] do
Envy.load(["config/.env.#{config_env()}"])
end
config_dir = System.get_env("CONFIG_DIR", "/run/secrets")
# System.get_env does not accept a non string default
port = get_var_from_path_or_env(config_dir, "PORT") || 8000
base_url = get_var_from_path_or_env(config_dir, "BASE_URL")
if !base_url do
raise "BASE_URL configuration option is required. See https://plausible.io/docs/self-hosting-configuration#server"
end
base_url = URI.parse(base_url)
if base_url.scheme not in ["http", "https"] do
raise "BASE_URL must start with `http` or `https`. Currently configured as `#{System.get_env("BASE_URL")}`"
end
secret_key_base = get_var_from_path_or_env(config_dir, "SECRET_KEY_BASE", nil)
case secret_key_base do
nil ->
raise "SECRET_KEY_BASE configuration option is required. See https://plausible.io/docs/self-hosting-configuration#server"
key when byte_size(key) < 32 ->
raise "SECRET_KEY_BASE must be at least 32 bytes long. See https://plausible.io/docs/self-hosting-configuration#server"
_ ->
nil
end
db_url =
get_var_from_path_or_env(
config_dir,
"DATABASE_URL",
"postgres://postgres:postgres@plausible_db:5432/plausible_db"
)
db_socket_dir = get_var_from_path_or_env(config_dir, "DATABASE_SOCKET_DIR")
admin_user = get_var_from_path_or_env(config_dir, "ADMIN_USER_NAME")
admin_email = get_var_from_path_or_env(config_dir, "ADMIN_USER_EMAIL")
admin_user_ids =
get_var_from_path_or_env(config_dir, "ADMIN_USER_IDS", "")
|> String.split(",")
|> Enum.map(fn id -> Integer.parse(id) end)
|> Enum.map(fn
{int, ""} -> int
_ -> nil
end)
|> Enum.filter(& &1)
admin_pwd = get_var_from_path_or_env(config_dir, "ADMIN_USER_PWD")
env = get_var_from_path_or_env(config_dir, "ENVIRONMENT", "prod")
mailer_adapter = get_var_from_path_or_env(config_dir, "MAILER_ADAPTER", "Bamboo.SMTPAdapter")
mailer_email = get_var_from_path_or_env(config_dir, "MAILER_EMAIL", "hello@plausible.local")
app_version = get_var_from_path_or_env(config_dir, "APP_VERSION", "0.0.1")
ch_db_url =
get_var_from_path_or_env(
config_dir,
"CLICKHOUSE_DATABASE_URL",
"http://plausible_events_db:8123/plausible_events_db"
)
{ch_flush_interval_ms, ""} =
config_dir
|> get_var_from_path_or_env("CLICKHOUSE_FLUSH_INTERVAL_MS", "5000")
|> Integer.parse()
{ch_max_buffer_size, ""} =
config_dir
|> get_var_from_path_or_env("CLICKHOUSE_MAX_BUFFER_SIZE", "10000")
|> Integer.parse()
### Mandatory params End
sentry_dsn = get_var_from_path_or_env(config_dir, "SENTRY_DSN")
honeycomb_api_key = get_var_from_path_or_env(config_dir, "HONEYCOMB_API_KEY")
honeycomb_dataset = get_var_from_path_or_env(config_dir, "HONEYCOMB_DATASET")
paddle_auth_code = get_var_from_path_or_env(config_dir, "PADDLE_VENDOR_AUTH_CODE")
google_cid = get_var_from_path_or_env(config_dir, "GOOGLE_CLIENT_ID")
google_secret = get_var_from_path_or_env(config_dir, "GOOGLE_CLIENT_SECRET")
slack_hook_url = get_var_from_path_or_env(config_dir, "SLACK_WEBHOOK")
twitter_consumer_key = get_var_from_path_or_env(config_dir, "TWITTER_CONSUMER_KEY")
twitter_consumer_secret = get_var_from_path_or_env(config_dir, "TWITTER_CONSUMER_SECRET")
twitter_token = get_var_from_path_or_env(config_dir, "TWITTER_ACCESS_TOKEN")
twitter_token_secret = get_var_from_path_or_env(config_dir, "TWITTER_ACCESS_TOKEN_SECRET")
postmark_api_key = get_var_from_path_or_env(config_dir, "POSTMARK_API_KEY")
cron_enabled =
config_dir
|> get_var_from_path_or_env("CRON_ENABLED", "false")
|> String.to_existing_atom()
custom_domain_server_ip = get_var_from_path_or_env(config_dir, "CUSTOM_DOMAIN_SERVER_IP")
custom_domain_server_user = get_var_from_path_or_env(config_dir, "CUSTOM_DOMAIN_SERVER_USER")
custom_domain_server_password =
get_var_from_path_or_env(config_dir, "CUSTOM_DOMAIN_SERVER_PASSWORD")
geolite2_country_db =
get_var_from_path_or_env(
config_dir,
"GEOLITE2_COUNTRY_DB",
Application.app_dir(:plausible) <> "/priv/geodb/dbip-country.mmdb"
)
disable_auth =
config_dir
|> get_var_from_path_or_env("DISABLE_AUTH", "false")
|> String.to_existing_atom()
enable_email_verification =
config_dir
|> get_var_from_path_or_env("ENABLE_EMAIL_VERIFICATION", "false")
|> String.to_existing_atom()
disable_registration =
config_dir
|> get_var_from_path_or_env("DISABLE_REGISTRATION", "false")
|> String.to_existing_atom()
hcaptcha_sitekey = get_var_from_path_or_env(config_dir, "HCAPTCHA_SITEKEY")
hcaptcha_secret = get_var_from_path_or_env(config_dir, "HCAPTCHA_SECRET")
log_level =
config_dir
|> get_var_from_path_or_env("LOG_LEVEL", "warn")
|> String.to_existing_atom()
domain_blacklist =
config_dir
|> get_var_from_path_or_env("DOMAIN_BLACKLIST", "")
|> String.split(",")
is_selfhost =
config_dir
|> get_var_from_path_or_env("SELFHOST", "true")
|> String.to_existing_atom()
custom_script_name =
config_dir
|> get_var_from_path_or_env("CUSTOM_SCRIPT_NAME", "script")
{site_limit, ""} =
config_dir
|> get_var_from_path_or_env("SITE_LIMIT", "50")
|> Integer.parse()
site_limit_exempt =
config_dir
|> get_var_from_path_or_env("SITE_LIMIT_EXEMPT", "")
|> String.split(",")
|> Enum.map(&String.trim/1)
disable_cron =
config_dir
|> get_var_from_path_or_env("DISABLE_CRON", "false")
|> String.to_existing_atom()
{user_agent_cache_limit, ""} =
config_dir
|> get_var_from_path_or_env("USER_AGENT_CACHE_LIMIT", "1000")
|> Integer.parse()
user_agent_cache_stats =
config_dir
|> get_var_from_path_or_env("USER_AGENT_CACHE_STATS", "false")
|> String.to_existing_atom()
config :plausible,
admin_user: admin_user,
admin_email: admin_email,
admin_pwd: admin_pwd,
environment: env,
mailer_email: mailer_email,
admin_user_ids: admin_user_ids,
site_limit: site_limit,
site_limit_exempt: site_limit_exempt,
is_selfhost: is_selfhost,
custom_script_name: custom_script_name,
domain_blacklist: domain_blacklist
config :plausible, :selfhost,
disable_authentication: disable_auth,
enable_email_verification: enable_email_verification,
disable_registration: if(!disable_auth, do: disable_registration, else: false)
config :plausible, PlausibleWeb.Endpoint,
url: [scheme: base_url.scheme, host: base_url.host, path: base_url.path, port: base_url.port],
http: [port: port, transport_options: [max_connections: :infinity]],
secret_key_base: secret_key_base
if is_nil(db_socket_dir) do
config :plausible, Plausible.Repo, url: db_url
else
config :plausible, Plausible.Repo,
socket_dir: db_socket_dir,
database: get_var_from_path_or_env(config_dir, "DATABASE_NAME", "plausible")
end
config :sentry,
dsn: sentry_dsn,
environment_name: env,
included_environments: ["prod", "staging"],
release: app_version,
tags: %{app_version: app_version},
enable_source_code_context: true,
root_source_code_path: [File.cwd!()]
config :plausible, :paddle, vendor_auth_code: paddle_auth_code
config :plausible, :google,
client_id: google_cid,
client_secret: google_secret
config :plausible, :slack, webhook: slack_hook_url
config :plausible, Plausible.ClickhouseRepo,
loggers: [Ecto.LogEntry],
queue_target: 500,
queue_interval: 2000,
url: ch_db_url,
flush_interval_ms: ch_flush_interval_ms,
max_buffer_size: ch_max_buffer_size
case mailer_adapter do
"Bamboo.PostmarkAdapter" ->
config :plausible, Plausible.Mailer,
adapter: :"Elixir.#{mailer_adapter}",
request_options: [recv_timeout: 10_000],
api_key: get_var_from_path_or_env(config_dir, "POSTMARK_API_KEY")
"Bamboo.SMTPAdapter" ->
config :plausible, Plausible.Mailer,
adapter: :"Elixir.#{mailer_adapter}",
server: get_var_from_path_or_env(config_dir, "SMTP_HOST_ADDR", "mail"),
hostname: base_url.host,
port: get_var_from_path_or_env(config_dir, "SMTP_HOST_PORT", "25"),
username: get_var_from_path_or_env(config_dir, "SMTP_USER_NAME"),
password: get_var_from_path_or_env(config_dir, "SMTP_USER_PWD"),
tls: :if_available,
allowed_tls_versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"],
ssl: get_var_from_path_or_env(config_dir, "SMTP_HOST_SSL_ENABLED") || false,
retries: get_var_from_path_or_env(config_dir, "SMTP_RETRIES") || 2,
no_mx_lookups: get_var_from_path_or_env(config_dir, "SMTP_MX_LOOKUPS_ENABLED") || true
"Bamboo.LocalAdapter" ->
config :plausible, Plausible.Mailer, adapter: Bamboo.LocalAdapter
"Bamboo.TestAdapter" ->
config :plausible, Plausible.Mailer, adapter: Bamboo.TestAdapter
_ ->
raise "Unknown mailer_adapter; expected SMTPAdapter or PostmarkAdapter"
end
config :plausible, :twitter,
consumer_key: twitter_consumer_key,
consumer_secret: twitter_consumer_secret,
token: twitter_token,
token_secret: twitter_token_secret
config :plausible, :custom_domain_server,
user: custom_domain_server_user,
password: custom_domain_server_password,
ip: custom_domain_server_ip
config :plausible, PlausibleWeb.Firewall,
blocklist:
get_var_from_path_or_env(config_dir, "IP_BLOCKLIST", "")
|> String.split(",")
|> Enum.map(&String.trim/1)
if config_env() == :prod && !disable_cron do
base_cron = [
# Daily at midnight
{"0 0 * * *", Plausible.Workers.RotateSalts},
#  hourly
{"0 * * * *", Plausible.Workers.ScheduleEmailReports},
# hourly
{"0 * * * *", Plausible.Workers.SendSiteSetupEmails},
# Daily at midnight
{"0 0 * * *", Plausible.Workers.FetchTweets},
# Daily at midday
{"0 12 * * *", Plausible.Workers.SendCheckStatsEmails},
# Every 15 minutes
{"*/15 * * * *", Plausible.Workers.SpikeNotifier},
# Every day at midnight
{"0 0 * * *", Plausible.Workers.CleanEmailVerificationCodes},
# Every day at 1am
{"0 1 * * *", Plausible.Workers.CleanInvitations}
]
extra_cron = [
# Daily at midday
{"0 12 * * *", Plausible.Workers.SendTrialNotifications},
# Daily at 14
{"0 14 * * *", Plausible.Workers.CheckUsage},
# Daily at 15
{"0 15 * * *", Plausible.Workers.NotifyAnnualRenewal},
# Every 10 minutes
{"*/10 * * * *", Plausible.Workers.ProvisionSslCertificates},
# Every midnight
{"0 0 * * *", Plausible.Workers.LockSites}
]
base_queues = [
rotate_salts: 1,
schedule_email_reports: 1,
send_email_reports: 1,
spike_notifications: 1,
fetch_tweets: 1,
check_stats_emails: 1,
site_setup_emails: 1,
clean_email_verification_codes: 1,
clean_invitations: 1
]
extra_queues = [
provision_ssl_certificates: 1,
trial_notification_emails: 1,
check_usage: 1,
notify_annual_renewal: 1,
lock_sites: 1
]
# Keep 30 days history
config :plausible, Oban,
repo: Plausible.Repo,
plugins: [{Oban.Plugins.Pruner, max_age: 2_592_000}],
queues: if(is_selfhost, do: base_queues, else: base_queues ++ extra_queues),
crontab: if(is_selfhost, do: base_cron, else: base_cron ++ extra_cron)
else
config :plausible, Oban,
repo: Plausible.Repo,
queues: false,
plugins: false
end
config :plausible, :hcaptcha,
sitekey: hcaptcha_sitekey,
secret: hcaptcha_secret
config :ref_inspector,
init: {Plausible.Release, :configure_ref_inspector}
config :ua_inspector,
init: {Plausible.Release, :configure_ua_inspector}
config :plausible, :user_agent_cache,
limit: user_agent_cache_limit,
stats: user_agent_cache_stats
config :hammer,
backend: {Hammer.Backend.ETS, [expiry_ms: 60_000 * 60 * 4, cleanup_interval_ms: 60_000 * 10]}
config :kaffy,
otp_app: :plausible,
ecto_repo: Plausible.Repo,
router: PlausibleWeb.Router,
admin_title: "Plausible Admin",
resources: [
auth: [
resources: [
user: [schema: Plausible.Auth.User, admin: Plausible.Auth.UserAdmin],
api_key: [schema: Plausible.Auth.ApiKey, admin: Plausible.Auth.ApiKeyAdmin]
]
],
sites: [
resources: [
site: [schema: Plausible.Site, admin: Plausible.SiteAdmin]
]
],
billing: [
resources: [
enterprise_plan: [
schema: Plausible.Billing.EnterprisePlan,
admin: Plausible.Billing.EnterprisePlanAdmin
]
]
]
]
if config_env() != :test && geolite2_country_db do
config :geolix,
databases: [
%{
id: :country,
adapter: Geolix.Adapter.MMDB2,
source: geolite2_country_db,
result_as: :raw
}
]
end
config :logger,
level: log_level,
backends: [:console]
config :logger, Sentry.LoggerBackend,
capture_log_messages: true,
level: :error,
excluded_domains: []
if honeycomb_api_key && honeycomb_dataset do
config :opentelemetry, :processors,
otel_batch_processor: %{
exporter:
{:opentelemetry_exporter,
%{
endpoints: ['https://api.honeycomb.io:443'],
headers: [
{"x-honeycomb-team", honeycomb_api_key},
{"x-honeycomb-dataset", honeycomb_dataset}
]
}}
}
end
config :tzdata,
:data_dir,
get_var_from_path_or_env(config_dir, "STORAGE_DIR", Application.app_dir(:tzdata, "priv"))